1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk1/window.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // Copyright:   (c) 1998 Robert Roebling, Julian Smart
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #ifdef __VMS
13 #define XWarpPointer XWARPPOINTER
14 #endif
15 
16 #include "wx/window.h"
17 
18 #ifndef WX_PRECOMP
19     #include "wx/intl.h"
20     #include "wx/log.h"
21     #include "wx/app.h"
22     #include "wx/utils.h"
23     #include "wx/frame.h"
24     #include "wx/dcclient.h"
25     #include "wx/menu.h"
26     #include "wx/dialog.h"
27     #include "wx/settings.h"
28     #include "wx/msgdlg.h"
29     #include "wx/textctrl.h"
30     #include "wx/combobox.h"
31     #include "wx/layout.h"
32     #include "wx/statusbr.h"
33     #include "wx/math.h"
34     #include "wx/module.h"
35 #endif
36 
37 #if wxUSE_DRAG_AND_DROP
38     #include "wx/dnd.h"
39 #endif
40 
41 #if wxUSE_TOOLTIPS
42     #include "wx/tooltip.h"
43 #endif
44 
45 #if wxUSE_CARET
46     #include "wx/caret.h"
47 #endif // wxUSE_CARET
48 
49 #include "wx/fontutil.h"
50 
51 #if wxDEBUG_LEVEL
52     #include "wx/thread.h"
53 #endif
54 
55 #include <ctype.h>
56 
57 #include "wx/gtk1/private.h"
58 #include <gdk/gdkprivate.h>
59 #include <gdk/gdkkeysyms.h>
60 #include <gdk/gdkx.h>
61 
62 #include <gtk/gtk.h>
63 #include <gtk/gtkprivate.h>
64 
65 #include "wx/gtk1/win_gtk.h"
66 
67 //-----------------------------------------------------------------------------
68 // documentation on internals
69 //-----------------------------------------------------------------------------
70 
71 /*
72    I have been asked several times about writing some documentation about
73    the GTK port of wxWidgets, especially its internal structures. Obviously,
74    you cannot understand wxGTK without knowing a little about the GTK, but
75    some more information about what the wxWindow, which is the base class
76    for all other window classes, does seems required as well.
77 
78    I)
79 
80    What does wxWindow do? It contains the common interface for the following
81    jobs of its descendants:
82 
83    1) Define the rudimentary behaviour common to all window classes, such as
84    resizing, intercepting user input (so as to make it possible to use these
85    events for special purposes in a derived class), window names etc.
86 
87    2) Provide the possibility to contain and manage children, if the derived
88    class is allowed to contain children, which holds true for those window
89    classes which do not display a native GTK widget. To name them, these
90    classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
91    work classes are a special case and are handled a bit differently from
92    the rest. The same holds true for the wxNotebook class.
93 
94    3) Provide the possibility to draw into a client area of a window. This,
95    too, only holds true for classes that do not display a native GTK widget
96    as above.
97 
98    4) Provide the entire mechanism for scrolling widgets. This actual inter-
99    face for this is usually in wxScrolledWindow, but the GTK implementation
100    is in this class.
101 
102    5) A multitude of helper or extra methods for special purposes, such as
103    Drag'n'Drop, managing validators etc.
104 
105    6) Display a border (sunken, raised, simple or none).
106 
107    Normally one might expect, that one wxWidgets window would always correspond
108    to one GTK widget. Under GTK, there is no such allround widget that has all
109    the functionality. Moreover, the GTK defines a client area as a different
110    widget from the actual widget you are handling. Last but not least some
111    special classes (e.g. wxFrame) handle different categories of widgets and
112    still have the possibility to draw something in the client area.
113    It was therefore required to write a special purpose GTK widget, that would
114    represent a client area in the sense of wxWidgets capable to do the jobs
115    2), 3) and 4). I have written this class and it resides in win_gtk.c of
116    this directory.
117 
118    All windows must have a widget, with which they interact with other under-
119    lying GTK widgets. It is this widget, e.g. that has to be resized etc and
120    the wxWindow class has a member variable called m_widget which holds a
121    pointer to this widget. When the window class represents a GTK native widget,
122    this is (in most cases) the only GTK widget the class manages. E.g. the
123    wxStaticText class handles only a GtkLabel widget a pointer to which you
124    can find in m_widget (defined in wxWindow)
125 
126    When the class has a client area for drawing into and for containing children
127    it has to handle the client area widget (of the type GtkPizza, defined in
128    win_gtk.c), but there could be any number of widgets, handled by a class
129    The common rule for all windows is only, that the widget that interacts with
130    the rest of GTK must be referenced in m_widget and all other widgets must be
131    children of this widget on the GTK level. The top-most widget, which also
132    represents the client area, must be in the m_wxwindow field and must be of
133    the type GtkPizza.
134 
135    As I said, the window classes that display a GTK native widget only have
136    one widget, so in the case of e.g. the wxButton class m_widget holds a
137    pointer to a GtkButton widget. But windows with client areas (for drawing
138    and children) have a m_widget field that is a pointer to a GtkScrolled-
139    Window and a m_wxwindow field that is pointer to a GtkPizza and this
140    one is (in the GTK sense) a child of the GtkScrolledWindow.
141 
142    If the m_wxwindow field is set, then all input to this widget is inter-
143    cepted and sent to the wxWidgets class. If not, all input to the widget
144    that gets pointed to by m_widget gets intercepted and sent to the class.
145 
146    II)
147 
148    The design of scrolling in wxWidgets is markedly different from that offered
149    by the GTK itself and therefore we cannot simply take it as it is. In GTK,
150    clicking on a scrollbar belonging to scrolled window will inevitably move
151    the window. In wxWidgets, the scrollbar will only emit an event, send this
152    to (normally) a wxScrolledWindow and that class will call ScrollWindow()
153    which actually moves the window and its subchildren. Note that GtkPizza
154    memorizes how much it has been scrolled but that wxWidgets forgets this
155    so that the two coordinates systems have to be kept in synch. This is done
156    in various places using the pizza->xoffset and pizza->yoffset values.
157 
158    III)
159 
160    Singularily the most broken code in GTK is the code that is supposed to
161    inform subwindows (child windows) about new positions. Very often, duplicate
162    events are sent without changes in size or position, equally often no
163    events are sent at all (All this is due to a bug in the GtkContainer code
164    which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
165    GTK's own system and it simply waits for size events for toplevel windows
166    and then iterates down the respective size events to all window. This has
167    the disadvantage that windows might get size events before the GTK widget
168    actually has the reported size. This doesn't normally pose any problem, but
169    the OpenGL drawing routines rely on correct behaviour. Therefore, I have
170    added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
171    i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
172    window that is used for OpenGL output really has that size (as reported by
173    GTK).
174 
175    IV)
176 
177    If someone at some point of time feels the immense desire to have a look at,
178    change or attempt to optimise the Refresh() logic, this person will need an
179    intimate understanding of what "draw" and "expose" events are and what
180    they are used for, in particular when used in connection with GTK's
181    own windowless widgets. Beware.
182 
183    V)
184 
185    Cursors, too, have been a constant source of pleasure. The main difficulty
186    is that a GdkWindow inherits a cursor if the programmer sets a new cursor
187    for the parent. To prevent this from doing too much harm, I use idle time
188    to set the cursor over and over again, starting from the toplevel windows
189    and ending with the youngest generation (speaking of parent and child windows).
190    Also don't forget that cursors (like much else) are connected to GdkWindows,
191    not GtkWidgets and that the "window" field of a GtkWidget might very well
192    point to the GdkWindow of the parent widget (-> "window-less widget") and
193    that the two obviously have very different meanings.
194 
195 */
196 
197 //-----------------------------------------------------------------------------
198 // data
199 //-----------------------------------------------------------------------------
200 
201 extern bool       g_blockEventsOnDrag;
202 extern bool       g_blockEventsOnScroll;
203 extern wxCursor   g_globalCursor;
204 
205 static GdkGC *g_eraseGC = NULL;
206 
207 // mouse capture state: the window which has it and if the mouse is currently
208 // inside it
209 static wxWindowGTK  *g_captureWindow = NULL;
210 static bool g_captureWindowHasMouse = false;
211 
212 wxWindowGTK  *g_focusWindow = NULL;
213 
214 // the last window which had the focus - this is normally never NULL (except
215 // if we never had focus at all) as even when g_focusWindow is NULL it still
216 // keeps its previous value
217 wxWindowGTK *g_focusWindowLast = NULL;
218 
219 // If a window get the focus set but has not been realized
220 // yet, defer setting the focus to idle time.
221 wxWindowGTK *g_delayedFocus = NULL;
222 
223 // hack: we need something to pass to gtk_menu_popup, so we store the time of
224 // the last click here (extern: used from gtk/menu.cpp)
225 guint32 wxGtkTimeLastClick = 0;
226 
227 // global variables because GTK+ DnD want to have the
228 // mouse event that caused it
229 GdkEvent *g_lastMouseEvent = NULL;
230 int g_lastButtonNumber = 0;
231 
232 extern bool g_mainThreadLocked;
233 
234 //-----------------------------------------------------------------------------
235 // debug
236 //-----------------------------------------------------------------------------
237 
238 #if wxUSE_THREADS
239 #   define DEBUG_MAIN_THREAD \
240         wxASSERT_MSG( !g_mainThreadLocked || !wxThread::IsMain(), \
241                       "GUI reentrancy detected" );
242 #else
243 #   define DEBUG_MAIN_THREAD
244 #endif
245 
246 // the trace mask used for the focus debugging messages
247 #define TRACE_FOCUS wxT("focus")
248 
249 //-----------------------------------------------------------------------------
250 // missing gdk functions
251 //-----------------------------------------------------------------------------
252 
253 void
gdk_window_warp_pointer(GdkWindow * window,gint x,gint y)254 gdk_window_warp_pointer (GdkWindow      *window,
255                          gint            x,
256                          gint            y)
257 {
258   GdkWindowPrivate *priv;
259 
260   if (!window)
261     window = GDK_ROOT_PARENT();
262 
263   priv = (GdkWindowPrivate*) window;
264 
265   if (!priv->destroyed)
266   {
267       XWarpPointer (priv->xdisplay,
268                     None,              /* not source window -> move from anywhere */
269                     priv->xwindow,  /* dest window */
270                     0, 0, 0, 0,        /* not source window -> move from anywhere */
271                     x, y );
272   }
273 }
274 
275 //-----------------------------------------------------------------------------
276 // idle system
277 //-----------------------------------------------------------------------------
278 
279 extern void wxapp_install_idle_handler();
280 extern bool g_isIdle;
281 
282 //-----------------------------------------------------------------------------
283 // local code (see below)
284 //-----------------------------------------------------------------------------
285 
286 // returns the child of win which currently has focus or NULL if not found
287 //
288 // Note: can't be static, needed by textctrl.cpp.
wxFindFocusedChild(wxWindowGTK * win)289 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
290 {
291     wxWindow *winFocus = wxWindowGTK::FindFocus();
292     if ( !winFocus )
293         return NULL;
294 
295     if ( winFocus == win )
296         return (wxWindow *)win;
297 
298     for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
299           node;
300           node = node->GetNext() )
301     {
302         wxWindow *child = wxFindFocusedChild(node->GetData());
303         if ( child )
304             return child;
305     }
306 
307     return NULL;
308 }
309 
draw_frame(GtkWidget * widget,wxWindowGTK * win)310 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
311 {
312     // wxUniversal widgets draw the borders and scrollbars themselves
313 #ifndef __WXUNIVERSAL__
314     if (!win->m_hasVMT)
315         return;
316 
317     int dw = 0;
318     int dh = 0;
319 
320     if (win->m_hasScrolling)
321     {
322         GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
323 
324         GtkRequisition vscroll_req;
325         vscroll_req.width = 2;
326         vscroll_req.height = 2;
327         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
328             (scroll_window->vscrollbar, &vscroll_req );
329 
330         GtkRequisition hscroll_req;
331         hscroll_req.width = 2;
332         hscroll_req.height = 2;
333         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
334             (scroll_window->hscrollbar, &hscroll_req );
335 
336         GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
337 
338         if (scroll_window->vscrollbar_visible)
339         {
340             dw += vscroll_req.width;
341             dw += scroll_class->scrollbar_spacing;
342         }
343 
344         if (scroll_window->hscrollbar_visible)
345         {
346             dh += hscroll_req.height;
347             dh += scroll_class->scrollbar_spacing;
348         }
349     }
350 
351     int dx = 0;
352     int dy = 0;
353     if (GTK_WIDGET_NO_WINDOW (widget))
354     {
355         dx += widget->allocation.x;
356         dy += widget->allocation.y;
357     }
358 
359     if (win->HasFlag(wxRAISED_BORDER))
360     {
361         gtk_draw_shadow( widget->style,
362                          widget->window,
363                          GTK_STATE_NORMAL,
364                          GTK_SHADOW_OUT,
365                          dx, dy,
366                          widget->allocation.width-dw, widget->allocation.height-dh );
367         return;
368     }
369 
370     if (win->HasFlag(wxSUNKEN_BORDER) || win->HasFlag(wxBORDER_THEME))
371     {
372         gtk_draw_shadow( widget->style,
373                          widget->window,
374                          GTK_STATE_NORMAL,
375                          GTK_SHADOW_IN,
376                          dx, dy,
377                          widget->allocation.width-dw, widget->allocation.height-dh );
378         return;
379     }
380 
381     if (win->HasFlag(wxSIMPLE_BORDER))
382     {
383         GdkGC *gc;
384         gc = gdk_gc_new( widget->window );
385         gdk_gc_set_foreground( gc, &widget->style->black );
386         gdk_draw_rectangle( widget->window, gc, FALSE,
387                          dx, dy,
388                          widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
389         gdk_gc_unref( gc );
390         return;
391     }
392 #endif // __WXUNIVERSAL__
393 }
394 
395 //-----------------------------------------------------------------------------
396 // "expose_event" of m_widget
397 //-----------------------------------------------------------------------------
398 
399 extern "C" {
gtk_window_own_expose_callback(GtkWidget * widget,GdkEventExpose * gdk_event,wxWindowGTK * win)400 static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
401 {
402     if (gdk_event->count > 0) return FALSE;
403 
404     draw_frame( widget, win );
405 
406     return TRUE;
407 }
408 }
409 
410 //-----------------------------------------------------------------------------
411 // "draw" of m_widget
412 //-----------------------------------------------------------------------------
413 
414 extern "C" {
gtk_window_own_draw_callback(GtkWidget * widget,GdkRectangle * WXUNUSED (rect),wxWindowGTK * win)415 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
416 {
417     draw_frame( widget, win );
418 }
419 }
420 
421 //-----------------------------------------------------------------------------
422 // "size_request" of m_widget
423 //-----------------------------------------------------------------------------
424 
425 // make it extern because wxStaticText needs to disconnect this one
426 extern "C" {
wxgtk_window_size_request_callback(GtkWidget * WXUNUSED (widget),GtkRequisition * requisition,wxWindow * win)427 void wxgtk_window_size_request_callback(GtkWidget *WXUNUSED(widget),
428                                         GtkRequisition *requisition,
429                                         wxWindow *win)
430 {
431     int w, h;
432     win->GetSize( &w, &h );
433     if (w < 2)
434         w = 2;
435     if (h < 2)
436         h = 2;
437 
438     requisition->height = h;
439     requisition->width = w;
440 }
441 }
442 
443 extern "C" {
444 static
wxgtk_combo_size_request_callback(GtkWidget * WXUNUSED (widget),GtkRequisition * requisition,wxComboBox * win)445 void wxgtk_combo_size_request_callback(GtkWidget *WXUNUSED(widget),
446                                        GtkRequisition *requisition,
447                                        wxComboBox *win)
448 {
449     // This callback is actually hooked into the text entry
450     // of the combo box, not the GtkHBox.
451 
452     int w, h;
453     win->GetSize( &w, &h );
454     if (w < 2)
455         w = 2;
456     if (h < 2)
457         h = 2;
458 
459     GtkCombo *gcombo = GTK_COMBO(win->m_widget);
460 
461     GtkRequisition entry_req;
462     entry_req.width = 2;
463     entry_req.height = 2;
464     (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
465         (gcombo->button, &entry_req );
466 
467     requisition->width = w - entry_req.width;
468     requisition->height = entry_req.height;
469 }
470 }
471 
472 //-----------------------------------------------------------------------------
473 // "expose_event" of m_wxwindow
474 //-----------------------------------------------------------------------------
475 
476 extern "C" {
gtk_window_expose_callback(GtkWidget * WXUNUSED (widget),GdkEventExpose * gdk_event,wxWindow * win)477 static int gtk_window_expose_callback( GtkWidget *WXUNUSED(widget),
478                                        GdkEventExpose *gdk_event,
479                                        wxWindow *win )
480 {
481     DEBUG_MAIN_THREAD
482 
483     if (g_isIdle)
484         wxapp_install_idle_handler();
485 
486     // This gets called immediately after an expose event
487     // under GTK 1.2 so we collect the calls and wait for
488     // the idle handler to pick things up.
489 
490     win->GetUpdateRegion().Union( gdk_event->area.x,
491                                   gdk_event->area.y,
492                                   gdk_event->area.width,
493                                   gdk_event->area.height );
494     win->m_clearRegion.Union( gdk_event->area.x,
495                                   gdk_event->area.y,
496                                   gdk_event->area.width,
497                                   gdk_event->area.height );
498 
499     // Actual redrawing takes place in idle time.
500     // win->GtkUpdate();
501 
502     return FALSE;
503 }
504 }
505 
506 //-----------------------------------------------------------------------------
507 // "event" of m_wxwindow
508 //-----------------------------------------------------------------------------
509 
510 // GTK thinks it is clever and filters out a certain amount of "unneeded"
511 // expose events. We need them, of course, so we override the main event
512 // procedure in GtkWidget by giving our own handler for all system events.
513 // There, we look for expose events ourselves whereas all other events are
514 // handled normally.
515 
516 extern "C" {
517 static
gtk_window_event_event_callback(GtkWidget * widget,GdkEventExpose * event,wxWindow * win)518 gint gtk_window_event_event_callback( GtkWidget *widget,
519                                       GdkEventExpose *event,
520                                       wxWindow *win )
521 {
522     if (event->type == GDK_EXPOSE)
523     {
524         gint ret = gtk_window_expose_callback( widget, event, win );
525         return ret;
526     }
527 
528     return FALSE;
529 }
530 }
531 
532 //-----------------------------------------------------------------------------
533 // "draw" of m_wxwindow
534 //-----------------------------------------------------------------------------
535 
536 // This callback is a complete replacement of the gtk_pizza_draw() function,
537 // which is disabled.
538 
539 extern "C" {
gtk_window_draw_callback(GtkWidget * widget,GdkRectangle * rect,wxWindow * win)540 static void gtk_window_draw_callback( GtkWidget *widget,
541                                       GdkRectangle *rect,
542                                       wxWindow *win )
543 {
544     DEBUG_MAIN_THREAD
545 
546     if (g_isIdle)
547         wxapp_install_idle_handler();
548 
549     // if there are any children we must refresh everything
550     //
551     // VZ: why?
552     if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
553             win->GetChildren().IsEmpty() )
554     {
555         return;
556     }
557 
558 #if 0
559     if (win->GetName())
560     {
561         wxPrintf( wxT("OnDraw from ") );
562         if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
563             wxPrintf( win->GetClassInfo()->GetClassName() );
564         wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
565                                          (int)rect->y,
566                                          (int)rect->width,
567                                          (int)rect->height );
568     }
569 #endif
570 
571 #ifndef __WXUNIVERSAL__
572     GtkPizza *pizza = GTK_PIZZA (widget);
573 
574     if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
575     {
576         wxWindow *parent = win->GetParent();
577         while (parent && !parent->IsTopLevel())
578             parent = parent->GetParent();
579         if (!parent)
580             parent = win;
581 
582         gtk_paint_flat_box (parent->m_widget->style,
583                             pizza->bin_window,
584                             GTK_STATE_NORMAL,
585                             GTK_SHADOW_NONE,
586                             rect,
587                             parent->m_widget,
588                             (char *)"base",
589                             0, 0, -1, -1);
590     }
591 #endif
592 
593     win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
594     win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
595 
596     // Update immediately, not in idle time.
597     win->GtkUpdate();
598 
599 #ifndef __WXUNIVERSAL__
600     // Redraw child widgets
601     GList *children = pizza->children;
602     while (children)
603     {
604         GtkPizzaChild *child = (GtkPizzaChild*) children->data;
605         children = children->next;
606 
607         GdkRectangle child_area;
608         if (gtk_widget_intersect (child->widget, rect, &child_area))
609         {
610             gtk_widget_draw (child->widget, &child_area /* NULL*/ );
611         }
612     }
613 #endif
614 }
615 }
616 
617 //-----------------------------------------------------------------------------
618 // "key_press_event" from any window
619 //-----------------------------------------------------------------------------
620 
621 // set WXTRACE to this to see the key event codes on the console
622 #define TRACE_KEYS  wxT("keyevent")
623 
624 // translates an X key symbol to WXK_XXX value
625 //
626 // if isChar is true it means that the value returned will be used for EVT_CHAR
627 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
628 // for example, while if it is false it means that the value is going to be
629 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
630 // WXK_NUMPAD_DIVIDE
wxTranslateKeySymToWXKey(KeySym keysym,bool isChar)631 static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
632 {
633     long key_code;
634 
635     switch ( keysym )
636     {
637         // Shift, Control and Alt don't generate the CHAR events at all
638         case GDK_Shift_L:
639         case GDK_Shift_R:
640             key_code = isChar ? 0 : WXK_SHIFT;
641             break;
642         case GDK_Control_L:
643         case GDK_Control_R:
644             key_code = isChar ? 0 : WXK_CONTROL;
645             break;
646         case GDK_Meta_L:
647         case GDK_Meta_R:
648         case GDK_Alt_L:
649         case GDK_Alt_R:
650         case GDK_Super_L:
651         case GDK_Super_R:
652             key_code = isChar ? 0 : WXK_ALT;
653             break;
654 
655         // neither do the toggle modifies
656         case GDK_Scroll_Lock:
657             key_code = isChar ? 0 : WXK_SCROLL;
658             break;
659 
660         case GDK_Caps_Lock:
661             key_code = isChar ? 0 : WXK_CAPITAL;
662             break;
663 
664         case GDK_Num_Lock:
665             key_code = isChar ? 0 : WXK_NUMLOCK;
666             break;
667 
668 
669         // various other special keys
670         case GDK_Menu:
671             key_code = WXK_MENU;
672             break;
673 
674         case GDK_Help:
675             key_code = WXK_HELP;
676             break;
677 
678         case GDK_BackSpace:
679             key_code = WXK_BACK;
680             break;
681 
682         case GDK_ISO_Left_Tab:
683         case GDK_Tab:
684             key_code = WXK_TAB;
685             break;
686 
687         case GDK_Linefeed:
688         case GDK_Return:
689             key_code = WXK_RETURN;
690             break;
691 
692         case GDK_Clear:
693             key_code = WXK_CLEAR;
694             break;
695 
696         case GDK_Pause:
697             key_code = WXK_PAUSE;
698             break;
699 
700         case GDK_Select:
701             key_code = WXK_SELECT;
702             break;
703 
704         case GDK_Print:
705             key_code = WXK_PRINT;
706             break;
707 
708         case GDK_Execute:
709             key_code = WXK_EXECUTE;
710             break;
711 
712         case GDK_Escape:
713             key_code = WXK_ESCAPE;
714             break;
715 
716         // cursor and other extended keyboard keys
717         case GDK_Delete:
718             key_code = WXK_DELETE;
719             break;
720 
721         case GDK_Home:
722             key_code = WXK_HOME;
723             break;
724 
725         case GDK_Left:
726             key_code = WXK_LEFT;
727             break;
728 
729         case GDK_Up:
730             key_code = WXK_UP;
731             break;
732 
733         case GDK_Right:
734             key_code = WXK_RIGHT;
735             break;
736 
737         case GDK_Down:
738             key_code = WXK_DOWN;
739             break;
740 
741         case GDK_Prior:     // == GDK_Page_Up
742             key_code = WXK_PAGEUP;
743             break;
744 
745         case GDK_Next:      // == GDK_Page_Down
746             key_code = WXK_PAGEDOWN;
747             break;
748 
749         case GDK_End:
750             key_code = WXK_END;
751             break;
752 
753         case GDK_Begin:
754             key_code = WXK_HOME;
755             break;
756 
757         case GDK_Insert:
758             key_code = WXK_INSERT;
759             break;
760 
761 
762         // numpad keys
763         case GDK_KP_0:
764         case GDK_KP_1:
765         case GDK_KP_2:
766         case GDK_KP_3:
767         case GDK_KP_4:
768         case GDK_KP_5:
769         case GDK_KP_6:
770         case GDK_KP_7:
771         case GDK_KP_8:
772         case GDK_KP_9:
773             key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
774             break;
775 
776         case GDK_KP_Space:
777             key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
778             break;
779 
780         case GDK_KP_Tab:
781             key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
782             break;
783 
784         case GDK_KP_Enter:
785             key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
786             break;
787 
788         case GDK_KP_F1:
789             key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
790             break;
791 
792         case GDK_KP_F2:
793             key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
794             break;
795 
796         case GDK_KP_F3:
797             key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
798             break;
799 
800         case GDK_KP_F4:
801             key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
802             break;
803 
804         case GDK_KP_Home:
805             key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
806             break;
807 
808         case GDK_KP_Left:
809             key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
810             break;
811 
812         case GDK_KP_Up:
813             key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
814             break;
815 
816         case GDK_KP_Right:
817             key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
818             break;
819 
820         case GDK_KP_Down:
821             key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
822             break;
823 
824         case GDK_KP_Prior: // == GDK_KP_Page_Up
825             key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP;
826             break;
827 
828         case GDK_KP_Next: // == GDK_KP_Page_Down
829             key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
830             break;
831 
832         case GDK_KP_End:
833             key_code = isChar ? WXK_END : WXK_NUMPAD_END;
834             break;
835 
836         case GDK_KP_Begin:
837             key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
838             break;
839 
840         case GDK_KP_Insert:
841             key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
842             break;
843 
844         case GDK_KP_Delete:
845             key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
846             break;
847 
848         case GDK_KP_Equal:
849             key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
850             break;
851 
852         case GDK_KP_Multiply:
853             key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
854             break;
855 
856         case GDK_KP_Add:
857             key_code = isChar ? '+' : WXK_NUMPAD_ADD;
858             break;
859 
860         case GDK_KP_Separator:
861             // FIXME: what is this?
862             key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
863             break;
864 
865         case GDK_KP_Subtract:
866             key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
867             break;
868 
869         case GDK_KP_Decimal:
870             key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
871             break;
872 
873         case GDK_KP_Divide:
874             key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
875             break;
876 
877 
878         // function keys
879         case GDK_F1:
880         case GDK_F2:
881         case GDK_F3:
882         case GDK_F4:
883         case GDK_F5:
884         case GDK_F6:
885         case GDK_F7:
886         case GDK_F8:
887         case GDK_F9:
888         case GDK_F10:
889         case GDK_F11:
890         case GDK_F12:
891             key_code = WXK_F1 + keysym - GDK_F1;
892             break;
893 
894         default:
895             key_code = 0;
896     }
897 
898     return key_code;
899 }
900 
wxIsAsciiKeysym(KeySym ks)901 static inline bool wxIsAsciiKeysym(KeySym ks)
902 {
903     return ks < 256;
904 }
905 
wxFillOtherKeyEventFields(wxKeyEvent & event,wxWindowGTK * win,GdkEventKey * gdk_event)906 static void wxFillOtherKeyEventFields(wxKeyEvent& event,
907                                       wxWindowGTK *win,
908                                       GdkEventKey *gdk_event)
909 {
910     int x = 0;
911     int y = 0;
912     GdkModifierType state;
913     if (gdk_event->window)
914         gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
915 
916     event.SetTimestamp( gdk_event->time );
917     event.SetId(win->GetId());
918     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
919     event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
920     event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
921     event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
922     event.m_rawCode = (wxUint32) gdk_event->keyval;
923     event.m_rawFlags = 0;
924 #if wxUSE_UNICODE
925 #if 0
926    // this is not gtk1.x
927    event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
928 #endif
929 #endif
930     wxGetMousePosition( &x, &y );
931     win->ScreenToClient( &x, &y );
932     event.m_x = x;
933     event.m_y = y;
934     event.SetEventObject( win );
935 }
936 
937 
938 static bool
wxTranslateGTKKeyEventToWx(wxKeyEvent & event,wxWindowGTK * win,GdkEventKey * gdk_event)939 wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
940                            wxWindowGTK *win,
941                            GdkEventKey *gdk_event)
942 {
943     // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
944     //     but only event->keyval which is quite useless to us, so remember
945     //     the last character from GDK_KEY_PRESS and reuse it as last resort
946     //
947     // NB: should be MT-safe as we're always called from the main thread only
948     static struct
949     {
950         KeySym keysym;
951         long   keycode;
952     } s_lastKeyPress = { 0, 0 };
953 
954     KeySym keysym = gdk_event->keyval;
955 
956     wxLogTrace(TRACE_KEYS, wxT("Key %s event: keysym = %ld"),
957                event.GetEventType() == wxEVT_KEY_UP ? wxT("release")
958                                                     : wxT("press"),
959                keysym);
960 
961     long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
962 
963     if ( !key_code )
964     {
965         // do we have the translation or is it a plain ASCII character?
966         if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
967         {
968             // we should use keysym if it is ASCII as X does some translations
969             // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
970             // which we don't want here (but which we do use for OnChar())
971             if ( !wxIsAsciiKeysym(keysym) )
972             {
973                 keysym = (KeySym)gdk_event->string[0];
974             }
975 
976             // we want to always get the same key code when the same key is
977             // pressed regardless of the state of the modifiers, i.e. on a
978             // standard US keyboard pressing '5' or '%' ('5' key with
979             // Shift) should result in the same key code in OnKeyDown():
980             // '5' (although OnChar() will get either '5' or '%').
981             //
982             // to do it we first translate keysym to keycode (== scan code)
983             // and then back but always using the lower register
984             Display *dpy = (Display *)wxGetDisplay();
985             KeyCode keycode = XKeysymToKeycode(dpy, keysym);
986 
987             wxLogTrace(TRACE_KEYS, wxT("\t-> keycode %d"), keycode);
988 
989             KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
990 
991             // use the normalized, i.e. lower register, keysym if we've
992             // got one
993             key_code = keysymNormalized ? keysymNormalized : keysym;
994 
995             // as explained above, we want to have lower register key codes
996             // normally but for the letter keys we want to have the upper ones
997             //
998             // NB: don't use XConvertCase() here, we want to do it for letters
999             // only
1000             key_code = toupper(key_code);
1001         }
1002         else // non ASCII key, what to do?
1003         {
1004             // by default, ignore it
1005             key_code = 0;
1006 
1007             // but if we have cached information from the last KEY_PRESS
1008             if ( gdk_event->type == GDK_KEY_RELEASE )
1009             {
1010                 // then reuse it
1011                 if ( keysym == s_lastKeyPress.keysym )
1012                 {
1013                     key_code = s_lastKeyPress.keycode;
1014                 }
1015             }
1016         }
1017 
1018         if ( gdk_event->type == GDK_KEY_PRESS )
1019         {
1020             // remember it to be reused for KEY_UP event later
1021             s_lastKeyPress.keysym = keysym;
1022             s_lastKeyPress.keycode = key_code;
1023         }
1024     }
1025 
1026     wxLogTrace(TRACE_KEYS, wxT("\t-> wxKeyCode %ld"), key_code);
1027 
1028     // sending unknown key events doesn't really make sense
1029     if ( !key_code )
1030         return false;
1031 
1032     // now fill all the other fields
1033     wxFillOtherKeyEventFields(event, win, gdk_event);
1034 
1035     event.m_keyCode = key_code;
1036 
1037     return true;
1038 }
1039 
1040 
1041 extern "C" {
gtk_window_key_press_callback(GtkWidget * widget,GdkEventKey * gdk_event,wxWindow * win)1042 static gint gtk_window_key_press_callback( GtkWidget *widget,
1043                                            GdkEventKey *gdk_event,
1044                                            wxWindow *win )
1045 {
1046     DEBUG_MAIN_THREAD
1047 
1048     if (g_isIdle)
1049         wxapp_install_idle_handler();
1050 
1051     if (!win->m_hasVMT)
1052         return FALSE;
1053     if (g_blockEventsOnDrag)
1054         return FALSE;
1055 
1056 
1057     wxKeyEvent event( wxEVT_KEY_DOWN );
1058     bool ret = false;
1059     bool return_after_IM = false;
1060 
1061     if ( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1062     {
1063         // Emit KEY_DOWN event
1064         ret = win->HandleWindowEvent( event );
1065     }
1066     else
1067     {
1068         // Return after IM processing as we cannot do
1069         // anything with it anyhow.
1070         return_after_IM = true;
1071     }
1072 
1073     // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1074     // in the "commit" handler.
1075 
1076     // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1077     // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1078     // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1079     // composed of more than one character, which means gdk_event->length will always
1080     // greater than one. When gtk_event->length == 1, this may be an ASCII character
1081     // and can be translated by wx.  However, when MBCS characters are sent by IM,
1082     // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1083     // nor should we pass it to controls. The following explanation was excerpted
1084     // from GDK documentation.
1085     // gint length : the length of string.
1086     // gchar *string : a null-terminated multi-byte string containing the composed
1087     // characters resulting from the key press. When text is being input, in a GtkEntry
1088     // for example, it is these characters which should be added to the input buffer.
1089     // When using Input Methods to support internationalized text input, the composed
1090     // characters appear here after the pre-editing has been completed.
1091 
1092     if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
1093     {
1094         // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1095         #if wxUSE_UNICODE   // GTK+ 1.2 is not UTF-8 based.
1096             const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
1097             if( !string )
1098                 return false;
1099         #else
1100             const char* string = gdk_event->string;
1101         #endif
1102 
1103         // Implement OnCharHook by checking ancestor top level windows
1104         wxWindow *parent = win;
1105         while (parent && !parent->IsTopLevel())
1106             parent = parent->GetParent();
1107 
1108         for( const wxChar* pstr = string; *pstr; pstr++ )
1109         {
1110         #if wxUSE_UNICODE
1111             event.m_uniChar = *pstr;
1112             // Backward compatible for ISO-8859-1
1113             event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1114         #else
1115             event.m_keyCode = *pstr;
1116         #endif
1117             if (parent)
1118             {
1119                 event.SetEventType( wxEVT_CHAR_HOOK );
1120                 ret = parent->HandleWindowEvent( event );
1121             }
1122             if (!ret)
1123             {
1124                 event.SetEventType(wxEVT_CHAR);
1125                 win->HandleWindowEvent( event );
1126             }
1127         }
1128         return true;
1129     }
1130 
1131     if (return_after_IM)
1132         return false;
1133 
1134 #if wxUSE_ACCEL
1135     if (!ret)
1136     {
1137         wxWindowGTK *ancestor = win;
1138         while (ancestor)
1139         {
1140             int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1141             if (command != -1)
1142             {
1143                 wxCommandEvent command_event( wxEVT_MENU, command );
1144                 ret = ancestor->HandleWindowEvent( command_event );
1145                 break;
1146             }
1147             if (ancestor->IsTopLevel())
1148                 break;
1149             ancestor = ancestor->GetParent();
1150         }
1151     }
1152 #endif // wxUSE_ACCEL
1153 
1154     // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1155     // will only be sent if it is not in an accelerator table.
1156     if (!ret)
1157     {
1158         long key_code;
1159         KeySym keysym = gdk_event->keyval;
1160         // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1161         key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
1162         if ( !key_code )
1163         {
1164             if ( wxIsAsciiKeysym(keysym) )
1165             {
1166                 // ASCII key
1167                 key_code = (unsigned char)keysym;
1168             }
1169             // gdk_event->string is actually deprecated
1170             else if ( gdk_event->length == 1 )
1171             {
1172                 key_code = (unsigned char)gdk_event->string[0];
1173             }
1174         }
1175 
1176         if ( key_code )
1177         {
1178             wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code);
1179 
1180             event.m_keyCode = key_code;
1181 
1182             // Implement OnCharHook by checking ancestor top level windows
1183             wxWindow *parent = win;
1184             while (parent && !parent->IsTopLevel())
1185                 parent = parent->GetParent();
1186             if (parent)
1187             {
1188                 event.SetEventType( wxEVT_CHAR_HOOK );
1189                 ret = parent->HandleWindowEvent( event );
1190             }
1191 
1192             if (!ret)
1193             {
1194                 event.SetEventType(wxEVT_CHAR);
1195                 ret = win->HandleWindowEvent( event );
1196             }
1197         }
1198     }
1199 
1200 
1201 
1202 
1203 
1204     // win is a control: tab can be propagated up
1205     if ( !ret &&
1206          ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1207 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1208 //     have this style, yet choose not to process this particular TAB in which
1209 //     case TAB must still work as a navigational character
1210 // JS: enabling again to make consistent with other platforms
1211 //     (with wxTE_PROCESS_TAB you have to call Navigate to get default
1212 //     navigation behaviour)
1213 #if wxUSE_TEXTCTRL
1214          (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
1215 #endif
1216          win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1217     {
1218         wxNavigationKeyEvent new_event;
1219         new_event.SetEventObject( win->GetParent() );
1220         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1221         new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1222         // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1223         new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1224         new_event.SetCurrentFocus( win );
1225         ret = win->GetParent()->HandleWindowEvent( new_event );
1226     }
1227 
1228     // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1229     if ( !ret &&
1230          (gdk_event->keyval == GDK_Escape) )
1231     {
1232         // however only do it if we have a Cancel button in the dialog,
1233         // otherwise the user code may get confused by the events from a
1234         // non-existing button and, worse, a wxButton might get button event
1235         // from another button which is not really expected
1236         wxWindow *winForCancel = win,
1237                  *btnCancel = NULL;
1238         while ( winForCancel )
1239         {
1240             btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1241             if ( btnCancel )
1242             {
1243                 // found a cancel button
1244                 break;
1245             }
1246 
1247             if ( winForCancel->IsTopLevel() )
1248             {
1249                 // no need to look further
1250                 break;
1251             }
1252 
1253             // maybe our parent has a cancel button?
1254             winForCancel = winForCancel->GetParent();
1255         }
1256 
1257         if ( btnCancel )
1258         {
1259             wxCommandEvent eventClick(wxEVT_BUTTON, wxID_CANCEL);
1260             eventClick.SetEventObject(btnCancel);
1261             ret = btnCancel->HandleWindowEvent(eventClick);
1262         }
1263     }
1264 
1265     if (ret)
1266     {
1267         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1268         return TRUE;
1269     }
1270 
1271     return FALSE;
1272 }
1273 }
1274 
1275 //-----------------------------------------------------------------------------
1276 // "key_release_event" from any window
1277 //-----------------------------------------------------------------------------
1278 
1279 extern "C" {
gtk_window_key_release_callback(GtkWidget * widget,GdkEventKey * gdk_event,wxWindowGTK * win)1280 static gint gtk_window_key_release_callback( GtkWidget *widget,
1281                                              GdkEventKey *gdk_event,
1282                                              wxWindowGTK *win )
1283 {
1284     DEBUG_MAIN_THREAD
1285 
1286     if (g_isIdle)
1287         wxapp_install_idle_handler();
1288 
1289     if (!win->m_hasVMT)
1290         return FALSE;
1291 
1292     if (g_blockEventsOnDrag)
1293         return FALSE;
1294 
1295     wxKeyEvent event( wxEVT_KEY_UP );
1296     if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1297     {
1298         // unknown key pressed, ignore (the event would be useless anyhow)
1299         return FALSE;
1300     }
1301 
1302     if ( !win->HandleWindowEvent( event ) )
1303         return FALSE;
1304 
1305     gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1306     return TRUE;
1307 }
1308 }
1309 
1310 // ============================================================================
1311 // the mouse events
1312 // ============================================================================
1313 
1314 // ----------------------------------------------------------------------------
1315 // mouse event processing helpers
1316 // ----------------------------------------------------------------------------
1317 
1318 // init wxMouseEvent with the info from GdkEventXXX struct
InitMouseEvent(wxWindowGTK * win,wxMouseEvent & event,T * gdk_event)1319 template<typename T> void InitMouseEvent(wxWindowGTK *win,
1320                                          wxMouseEvent& event,
1321                                          T *gdk_event)
1322 {
1323     event.SetTimestamp( gdk_event->time );
1324     event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1325     event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1326     event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1327     event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1328     event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1329     event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1330     event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1331     if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1332     {
1333        event.m_linesPerAction = 3;
1334        event.m_columnsPerAction = 3;
1335        event.m_wheelDelta = 120;
1336        if (((GdkEventButton*)gdk_event)->button == 4)
1337            event.m_wheelRotation = 120;
1338        else if (((GdkEventButton*)gdk_event)->button == 5)
1339            event.m_wheelRotation = -120;
1340     }
1341 
1342     wxPoint pt = win->GetClientAreaOrigin();
1343     event.m_x = (wxCoord)gdk_event->x - pt.x;
1344     event.m_y = (wxCoord)gdk_event->y - pt.y;
1345 
1346     event.SetEventObject( win );
1347     event.SetId( win->GetId() );
1348     event.SetTimestamp( gdk_event->time );
1349 }
1350 
AdjustEventButtonState(wxMouseEvent & event)1351 static void AdjustEventButtonState(wxMouseEvent& event)
1352 {
1353     // GDK reports the old state of the button for a button press event, but
1354     // for compatibility with MSW and common sense we want m_leftDown be true
1355     // for a LEFT_DOWN event, not FALSE, so we will invert
1356     // left/right/middleDown for the corresponding click events
1357 
1358     if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1359         (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1360         (event.GetEventType() == wxEVT_LEFT_UP))
1361     {
1362         event.m_leftDown = !event.m_leftDown;
1363         return;
1364     }
1365 
1366     if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1367         (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1368         (event.GetEventType() == wxEVT_MIDDLE_UP))
1369     {
1370         event.m_middleDown = !event.m_middleDown;
1371         return;
1372     }
1373 
1374     if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1375         (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1376         (event.GetEventType() == wxEVT_RIGHT_UP))
1377     {
1378         event.m_rightDown = !event.m_rightDown;
1379         return;
1380     }
1381 }
1382 
1383 // find the window to send the mouse event too
1384 static
FindWindowForMouseEvent(wxWindowGTK * win,wxCoord & x,wxCoord & y)1385 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1386 {
1387     wxCoord xx = x;
1388     wxCoord yy = y;
1389 
1390     if (win->m_wxwindow)
1391     {
1392         GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1393         xx += pizza->xoffset;
1394         yy += pizza->yoffset;
1395     }
1396 
1397     wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1398     while (node)
1399     {
1400         wxWindowGTK *child = node->GetData();
1401 
1402         node = node->GetNext();
1403         if (!child->IsShown())
1404             continue;
1405 
1406         if (child->IsTransparentForMouse())
1407         {
1408             // wxStaticBox is transparent in the box itself
1409             int xx1 = child->m_x;
1410             int yy1 = child->m_y;
1411             int xx2 = child->m_x + child->m_width;
1412             int yy2 = child->m_y + child->m_height;
1413 
1414             // left
1415             if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
1416             // right
1417                 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
1418             // top
1419                 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
1420             // bottom
1421                 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
1422             {
1423                 win = child;
1424                 x -= child->m_x;
1425                 y -= child->m_y;
1426                 break;
1427             }
1428 
1429         }
1430         else
1431         {
1432             if ((child->m_wxwindow == NULL) &&
1433                 (child->m_x <= xx) &&
1434                 (child->m_y <= yy) &&
1435                 (child->m_x+child->m_width  >= xx) &&
1436                 (child->m_y+child->m_height >= yy))
1437             {
1438                 win = child;
1439                 x -= child->m_x;
1440                 y -= child->m_y;
1441                 break;
1442             }
1443         }
1444     }
1445 
1446     return win;
1447 }
1448 
1449 //-----------------------------------------------------------------------------
1450 // "button_press_event"
1451 //-----------------------------------------------------------------------------
1452 
1453 extern "C" {
gtk_window_button_press_callback(GtkWidget * widget,GdkEventButton * gdk_event,wxWindowGTK * win)1454 static gint gtk_window_button_press_callback( GtkWidget *widget,
1455                                               GdkEventButton *gdk_event,
1456                                               wxWindowGTK *win )
1457 {
1458     DEBUG_MAIN_THREAD
1459 
1460     if (g_isIdle)
1461         wxapp_install_idle_handler();
1462 
1463 /*
1464     wxPrintf( wxT("1) OnButtonPress from ") );
1465     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1466         wxPrintf( win->GetClassInfo()->GetClassName() );
1467     wxPrintf( wxT(".\n") );
1468 */
1469     if (!win->m_hasVMT) return FALSE;
1470     if (g_blockEventsOnDrag) return TRUE;
1471     if (g_blockEventsOnScroll) return TRUE;
1472 
1473     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1474 
1475     g_lastButtonNumber = gdk_event->button;
1476 
1477     if (win->m_wxwindow && (g_focusWindow != win) && win->IsFocusable())
1478     {
1479         gtk_widget_grab_focus( win->m_wxwindow );
1480 /*
1481         wxPrintf( wxT("GrabFocus from ") );
1482         if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1483             wxPrintf( win->GetClassInfo()->GetClassName() );
1484         wxPrintf( wxT(".\n") );
1485 */
1486     }
1487 
1488     // GDK sends surplus button down events
1489     // before a double click event. We
1490     // need to filter these out.
1491     if (gdk_event->type == GDK_BUTTON_PRESS)
1492     {
1493         GdkEvent *peek_event = gdk_event_peek();
1494         if (peek_event)
1495         {
1496             if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1497                 (peek_event->type == GDK_3BUTTON_PRESS))
1498             {
1499                 gdk_event_free( peek_event );
1500                 return TRUE;
1501             }
1502             else
1503             {
1504                 gdk_event_free( peek_event );
1505             }
1506         }
1507     }
1508 
1509     wxEventType event_type = wxEVT_NULL;
1510 
1511     if (gdk_event->button == 1)
1512     {
1513         // note that GDK generates triple click events which are not supported
1514         // by wxWidgets but still have to be passed to the app as otherwise
1515         // clicks would simply go missing
1516         switch (gdk_event->type)
1517         {
1518             // we shouldn't get triple clicks at all for GTK2 because we
1519             // suppress them artificially using the code above but we still
1520             // should map them to something for GTK1 and not just ignore them
1521             // as this would lose clicks
1522             case GDK_3BUTTON_PRESS:     // we could also map this to DCLICK...
1523             case GDK_BUTTON_PRESS:
1524                 event_type = wxEVT_LEFT_DOWN;
1525                 break;
1526 
1527             case GDK_2BUTTON_PRESS:
1528                 event_type = wxEVT_LEFT_DCLICK;
1529                 break;
1530 
1531             default:
1532                 // just to silence gcc warnings
1533                 ;
1534         }
1535     }
1536     else if (gdk_event->button == 2)
1537     {
1538         switch (gdk_event->type)
1539         {
1540             case GDK_3BUTTON_PRESS:
1541             case GDK_BUTTON_PRESS:
1542                 event_type = wxEVT_MIDDLE_DOWN;
1543                 break;
1544 
1545             case GDK_2BUTTON_PRESS:
1546                 event_type = wxEVT_MIDDLE_DCLICK;
1547                 break;
1548 
1549             default:
1550                 ;
1551         }
1552     }
1553     else if (gdk_event->button == 3)
1554     {
1555         switch (gdk_event->type)
1556         {
1557             case GDK_3BUTTON_PRESS:
1558             case GDK_BUTTON_PRESS:
1559                 event_type = wxEVT_RIGHT_DOWN;
1560                 break;
1561 
1562             case GDK_2BUTTON_PRESS:
1563                 event_type = wxEVT_RIGHT_DCLICK;
1564                 break;
1565 
1566             default:
1567                 ;
1568         }
1569     }
1570     else if (gdk_event->button == 4 || gdk_event->button == 5)
1571     {
1572         if (gdk_event->type == GDK_BUTTON_PRESS )
1573         {
1574             event_type = wxEVT_MOUSEWHEEL;
1575         }
1576     }
1577 
1578     if ( event_type == wxEVT_NULL )
1579     {
1580         // unknown mouse button or click type
1581         return FALSE;
1582     }
1583 
1584     g_lastMouseEvent = (GdkEvent*) gdk_event;
1585 
1586     wxMouseEvent event( event_type );
1587     InitMouseEvent( win, event, gdk_event );
1588 
1589     AdjustEventButtonState(event);
1590 
1591     // wxListBox actually gets mouse events from the item, so we need to give it
1592     // a chance to correct this
1593     win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1594 
1595     // find the correct window to send the event to: it may be a different one
1596     // from the one which got it at GTK+ level because some controls don't have
1597     // their own X window and thus cannot get any events.
1598     if ( !g_captureWindow )
1599         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1600 
1601     wxGtkTimeLastClick = gdk_event->time;
1602 
1603     if (event_type == wxEVT_LEFT_DCLICK)
1604     {
1605         // GTK 1.2 crashes when intercepting double
1606         // click events from both wxSpinButton and
1607         // wxSpinCtrl
1608         if (GTK_IS_SPIN_BUTTON(win->m_widget))
1609         {
1610             // Just disable this event for now.
1611             return FALSE;
1612         }
1613     }
1614 
1615     if (win->HandleWindowEvent( event ))
1616     {
1617         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1618         g_lastMouseEvent = NULL;
1619         return TRUE;
1620     }
1621     g_lastMouseEvent = NULL;
1622 
1623     if (event_type == wxEVT_RIGHT_DOWN)
1624     {
1625         // generate a "context menu" event: this is similar to right mouse
1626         // click under many GUIs except that it is generated differently
1627         // (right up under MSW, ctrl-click under Mac, right down here) and
1628         //
1629         // (a) it's a command event and so is propagated to the parent
1630         // (b) under some ports it can be generated from kbd too
1631         // (c) it uses screen coords (because of (a))
1632         const wxPoint pos = win->ClientToScreen(event.GetPosition());
1633         return win->WXSendContextMenuEvent(pos);
1634     }
1635 
1636     return FALSE;
1637 }
1638 }
1639 
1640 //-----------------------------------------------------------------------------
1641 // "button_release_event"
1642 //-----------------------------------------------------------------------------
1643 
1644 extern "C" {
gtk_window_button_release_callback(GtkWidget * widget,GdkEventButton * gdk_event,wxWindowGTK * win)1645 static gint gtk_window_button_release_callback( GtkWidget *widget,
1646                                                 GdkEventButton *gdk_event,
1647                                                 wxWindowGTK *win )
1648 {
1649     DEBUG_MAIN_THREAD
1650 
1651     if (g_isIdle)
1652         wxapp_install_idle_handler();
1653 
1654     if (!win->m_hasVMT) return FALSE;
1655     if (g_blockEventsOnDrag) return FALSE;
1656     if (g_blockEventsOnScroll) return FALSE;
1657 
1658     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1659 
1660     g_lastButtonNumber = 0;
1661 
1662     wxEventType event_type = wxEVT_NULL;
1663 
1664     switch (gdk_event->button)
1665     {
1666         case 1:
1667             event_type = wxEVT_LEFT_UP;
1668             break;
1669 
1670         case 2:
1671             event_type = wxEVT_MIDDLE_UP;
1672             break;
1673 
1674         case 3:
1675             event_type = wxEVT_RIGHT_UP;
1676             break;
1677 
1678         default:
1679             // unknown button, don't process
1680             return FALSE;
1681     }
1682 
1683     g_lastMouseEvent = (GdkEvent*) gdk_event;
1684 
1685     wxMouseEvent event( event_type );
1686     InitMouseEvent( win, event, gdk_event );
1687 
1688     AdjustEventButtonState(event);
1689 
1690     // same wxListBox hack as above
1691     win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1692 
1693     if ( !g_captureWindow )
1694         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1695 
1696     if (win->HandleWindowEvent( event ))
1697     {
1698         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1699         return TRUE;
1700     }
1701 
1702     return FALSE;
1703 }
1704 }
1705 
1706 //-----------------------------------------------------------------------------
1707 // "motion_notify_event"
1708 //-----------------------------------------------------------------------------
1709 
1710 extern "C" {
gtk_window_motion_notify_callback(GtkWidget * widget,GdkEventMotion * gdk_event,wxWindowGTK * win)1711 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1712                                                GdkEventMotion *gdk_event,
1713                                                wxWindowGTK *win )
1714 {
1715     DEBUG_MAIN_THREAD
1716 
1717     if (g_isIdle)
1718         wxapp_install_idle_handler();
1719 
1720     if (!win->m_hasVMT) return FALSE;
1721     if (g_blockEventsOnDrag) return FALSE;
1722     if (g_blockEventsOnScroll) return FALSE;
1723 
1724     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1725 
1726     if (gdk_event->is_hint)
1727     {
1728         int x = 0;
1729         int y = 0;
1730         GdkModifierType state;
1731         gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1732         gdk_event->x = x;
1733         gdk_event->y = y;
1734     }
1735 
1736     g_lastMouseEvent = (GdkEvent*) gdk_event;
1737 
1738 /*
1739     printf( "OnMotion from " );
1740     if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1741       printf( win->GetClassInfo()->GetClassName() );
1742     printf( ".\n" );
1743 */
1744 
1745     wxMouseEvent event( wxEVT_MOTION );
1746     InitMouseEvent(win, event, gdk_event);
1747 
1748     if ( g_captureWindow )
1749     {
1750         // synthetize a mouse enter or leave event if needed
1751         GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1752         // This seems to be necessary and actually been added to
1753         // GDK itself in version 2.0.X
1754         gdk_flush();
1755 
1756         bool hasMouse = winUnderMouse == gdk_event->window;
1757         if ( hasMouse != g_captureWindowHasMouse )
1758         {
1759             // the mouse changed window
1760             g_captureWindowHasMouse = hasMouse;
1761 
1762             wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1763                                                         : wxEVT_LEAVE_WINDOW);
1764             InitMouseEvent(win, eventM, gdk_event);
1765             eventM.SetEventObject(win);
1766             win->HandleWindowEvent(eventM);
1767         }
1768     }
1769     else // no capture
1770     {
1771         win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1772     }
1773 
1774     bool ret = win->HandleWindowEvent( event );
1775     g_lastMouseEvent = NULL;
1776 
1777     if ( ret )
1778     {
1779         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1780     }
1781 
1782     return ret ? TRUE : FALSE;
1783 }
1784 }
1785 
1786 //-----------------------------------------------------------------------------
1787 // "focus_in_event"
1788 //-----------------------------------------------------------------------------
1789 
1790 // send the wxChildFocusEvent and wxFocusEvent, common code of
1791 // gtk_window_focus_in_callback() and SetFocus()
DoSendFocusEvents(wxWindow * win)1792 static bool DoSendFocusEvents(wxWindow *win)
1793 {
1794     // Notify the parent keeping track of focus for the kbd navigation
1795     // purposes that we got it.
1796     wxChildFocusEvent eventChildFocus(win);
1797     (void)win->HandleWindowEvent(eventChildFocus);
1798 
1799     wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
1800     eventFocus.SetEventObject(win);
1801 
1802     return win->HandleWindowEvent(eventFocus);
1803 }
1804 
1805 extern "C" {
gtk_window_focus_in_callback(GtkWidget * widget,GdkEvent * WXUNUSED (event),wxWindow * win)1806 static gint gtk_window_focus_in_callback( GtkWidget *widget,
1807                                           GdkEvent *WXUNUSED(event),
1808                                           wxWindow *win )
1809 {
1810     DEBUG_MAIN_THREAD
1811 
1812     if (g_isIdle)
1813         wxapp_install_idle_handler();
1814 
1815     g_focusWindowLast =
1816     g_focusWindow = win;
1817 
1818     wxLogTrace(TRACE_FOCUS,
1819                wxT("%s: focus in"), win->GetName().c_str());
1820 
1821 #ifdef HAVE_XIM
1822     if (win->m_ic)
1823         gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1824 #endif
1825 
1826 #if wxUSE_CARET
1827     // caret needs to be informed about focus change
1828     wxCaret *caret = win->GetCaret();
1829     if ( caret )
1830     {
1831         caret->OnSetFocus();
1832     }
1833 #endif // wxUSE_CARET
1834 
1835     // does the window itself think that it has the focus?
1836     if ( !win->m_hasFocus )
1837     {
1838         // not yet, notify it
1839         win->m_hasFocus = true;
1840 
1841         if ( DoSendFocusEvents(win) )
1842         {
1843            gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1844            return TRUE;
1845         }
1846     }
1847 
1848     return FALSE;
1849 }
1850 }
1851 
1852 //-----------------------------------------------------------------------------
1853 // "focus_out_event"
1854 //-----------------------------------------------------------------------------
1855 
1856 extern "C" {
gtk_window_focus_out_callback(GtkWidget * WXUNUSED (widget),GdkEventFocus * WXUNUSED (gdk_event),wxWindowGTK * win)1857 static gint gtk_window_focus_out_callback( GtkWidget *WXUNUSED(widget),
1858                                            GdkEventFocus *WXUNUSED(gdk_event),
1859                                            wxWindowGTK *win )
1860 {
1861     DEBUG_MAIN_THREAD
1862 
1863     if (g_isIdle)
1864         wxapp_install_idle_handler();
1865 
1866     wxLogTrace( TRACE_FOCUS,
1867                 wxT("%s: focus out"), win->GetName().c_str() );
1868 
1869 
1870     wxWindowGTK *winFocus = wxFindFocusedChild(win);
1871     if ( winFocus )
1872         win = winFocus;
1873 
1874     g_focusWindow = NULL;
1875 
1876 #ifdef HAVE_XIM
1877     if (win->m_ic)
1878         gdk_im_end();
1879 #endif
1880 
1881 #if wxUSE_CARET
1882     // caret needs to be informed about focus change
1883     wxCaret *caret = win->GetCaret();
1884     if ( caret )
1885     {
1886         caret->OnKillFocus();
1887     }
1888 #endif // wxUSE_CARET
1889 
1890     // don't send the window a kill focus event if it thinks that it doesn't
1891     // have focus already
1892     if ( win->m_hasFocus )
1893     {
1894         win->m_hasFocus = false;
1895 
1896         wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1897         event.SetEventObject( win );
1898 
1899         // even if we did process the event in wx code, still let GTK itself
1900         // process it too as otherwise bad things happen, especially in GTK2
1901         // where the text control simply aborts the program if it doesn't get
1902         // the matching focus out event
1903         (void)win->HandleWindowEvent( event );
1904     }
1905 
1906     return FALSE;
1907 }
1908 }
1909 
1910 //-----------------------------------------------------------------------------
1911 // "enter_notify_event"
1912 //-----------------------------------------------------------------------------
1913 
1914 extern "C" {
1915 static
gtk_window_enter_callback(GtkWidget * widget,GdkEventCrossing * gdk_event,wxWindowGTK * win)1916 gint gtk_window_enter_callback( GtkWidget *widget,
1917                                 GdkEventCrossing *gdk_event,
1918                                 wxWindowGTK *win )
1919 {
1920     DEBUG_MAIN_THREAD
1921 
1922     if (g_isIdle)
1923         wxapp_install_idle_handler();
1924 
1925     if (!win->m_hasVMT) return FALSE;
1926     if (g_blockEventsOnDrag) return FALSE;
1927 
1928     // Event was emitted after a grab
1929     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
1930 
1931     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1932 
1933     int x = 0;
1934     int y = 0;
1935     GdkModifierType state = (GdkModifierType)0;
1936 
1937     gdk_window_get_pointer( widget->window, &x, &y, &state );
1938 
1939     wxMouseEvent event( wxEVT_ENTER_WINDOW );
1940     InitMouseEvent(win, event, gdk_event);
1941     wxPoint pt = win->GetClientAreaOrigin();
1942     event.m_x = x + pt.x;
1943     event.m_y = y + pt.y;
1944 
1945     if (win->HandleWindowEvent( event ))
1946     {
1947        gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1948        return TRUE;
1949     }
1950 
1951     return FALSE;
1952 }
1953 }
1954 
1955 //-----------------------------------------------------------------------------
1956 // "leave_notify_event"
1957 //-----------------------------------------------------------------------------
1958 
1959 extern "C" {
gtk_window_leave_callback(GtkWidget * widget,GdkEventCrossing * gdk_event,wxWindowGTK * win)1960 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
1961 {
1962     DEBUG_MAIN_THREAD
1963 
1964     if (g_isIdle)
1965         wxapp_install_idle_handler();
1966 
1967     if (!win->m_hasVMT) return FALSE;
1968     if (g_blockEventsOnDrag) return FALSE;
1969 
1970     // Event was emitted after an ungrab
1971     if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
1972 
1973     if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1974 
1975     wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1976     event.SetTimestamp( gdk_event->time );
1977     event.SetEventObject( win );
1978 
1979     int x = 0;
1980     int y = 0;
1981     GdkModifierType state = (GdkModifierType)0;
1982 
1983     gdk_window_get_pointer( widget->window, &x, &y, &state );
1984 
1985     event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
1986     event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
1987     event.m_altDown = (state & GDK_MOD1_MASK) != 0;
1988     event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
1989     event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
1990     event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
1991     event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
1992 
1993     wxPoint pt = win->GetClientAreaOrigin();
1994     event.m_x = x + pt.x;
1995     event.m_y = y + pt.y;
1996 
1997     if (win->HandleWindowEvent( event ))
1998     {
1999         gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
2000         return TRUE;
2001     }
2002 
2003     return FALSE;
2004 }
2005 }
2006 
2007 //-----------------------------------------------------------------------------
2008 // "value_changed" from m_vAdjust
2009 //-----------------------------------------------------------------------------
2010 
2011 extern "C" {
gtk_window_vscroll_callback(GtkAdjustment * adjust,SCROLLBAR_CBACK_ARG wxWindowGTK * win)2012 static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
2013                                          SCROLLBAR_CBACK_ARG
2014                                          wxWindowGTK *win )
2015 {
2016     DEBUG_MAIN_THREAD
2017 
2018     if (g_isIdle)
2019         wxapp_install_idle_handler();
2020 
2021     if (g_blockEventsOnDrag) return;
2022 
2023     if (!win->m_hasVMT) return;
2024 
2025     float diff = adjust->value - win->m_oldVerticalPos;
2026     if (fabs(diff) < 0.2) return;
2027 
2028     win->m_oldVerticalPos = adjust->value;
2029 
2030     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2031     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
2032 
2033     int value = (int)(adjust->value+0.5);
2034 
2035     wxScrollWinEvent event( command, value, wxVERTICAL );
2036     event.SetEventObject( win );
2037     win->HandleWindowEvent( event );
2038 }
2039 }
2040 
2041 //-----------------------------------------------------------------------------
2042 // "value_changed" from m_hAdjust
2043 //-----------------------------------------------------------------------------
2044 
2045 extern "C" {
gtk_window_hscroll_callback(GtkAdjustment * adjust,SCROLLBAR_CBACK_ARG wxWindowGTK * win)2046 static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
2047                                          SCROLLBAR_CBACK_ARG
2048                                          wxWindowGTK *win )
2049 {
2050     DEBUG_MAIN_THREAD
2051 
2052     if (g_isIdle)
2053         wxapp_install_idle_handler();
2054 
2055     if (g_blockEventsOnDrag) return;
2056     if (!win->m_hasVMT) return;
2057 
2058     float diff = adjust->value - win->m_oldHorizontalPos;
2059     if (fabs(diff) < 0.2) return;
2060 
2061     GtkScrolledWindow   *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2062     wxEventType         command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
2063 
2064     win->m_oldHorizontalPos = adjust->value;
2065 
2066     int value = (int)(adjust->value+0.5);
2067 
2068     wxScrollWinEvent event( command, value, wxHORIZONTAL );
2069     event.SetEventObject( win );
2070     win->HandleWindowEvent( event );
2071 }
2072 }
2073 
2074 //-----------------------------------------------------------------------------
2075 // "button_press_event" from scrollbar
2076 //-----------------------------------------------------------------------------
2077 
2078 extern "C" {
gtk_scrollbar_button_press_callback(GtkRange * widget,GdkEventButton * gdk_event,wxWindowGTK * win)2079 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2080                                                  GdkEventButton *gdk_event,
2081                                                  wxWindowGTK *win)
2082 {
2083     DEBUG_MAIN_THREAD
2084 
2085     if (g_isIdle)
2086         wxapp_install_idle_handler();
2087 
2088 
2089     g_blockEventsOnScroll = true;
2090 
2091     // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2092     win->m_isScrolling = (gdk_event->window == widget->slider);
2093 
2094     return FALSE;
2095 }
2096 }
2097 
2098 //-----------------------------------------------------------------------------
2099 // "button_release_event" from scrollbar
2100 //-----------------------------------------------------------------------------
2101 
2102 extern "C" {
gtk_scrollbar_button_release_callback(GtkRange * widget,GdkEventButton * WXUNUSED (gdk_event),wxWindowGTK * win)2103 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2104                                                    GdkEventButton *WXUNUSED(gdk_event),
2105                                                    wxWindowGTK *win)
2106 {
2107     DEBUG_MAIN_THREAD
2108 
2109 //  don't test here as we can release the mouse while being over
2110 //  a different window than the slider
2111 //
2112 //    if (gdk_event->window != widget->slider) return FALSE;
2113 
2114     g_blockEventsOnScroll = false;
2115 
2116     if (win->m_isScrolling)
2117     {
2118         wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2119         int value = -1;
2120         int dir = -1;
2121 
2122         GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2123         if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2124         {
2125             value = (int)(win->m_hAdjust->value+0.5);
2126             dir = wxHORIZONTAL;
2127         }
2128         if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2129         {
2130             value = (int)(win->m_vAdjust->value+0.5);
2131             dir = wxVERTICAL;
2132         }
2133 
2134         wxScrollWinEvent event( command, value, dir );
2135         event.SetEventObject( win );
2136         win->HandleWindowEvent( event );
2137     }
2138 
2139     win->m_isScrolling = false;
2140 
2141     return FALSE;
2142 }
2143 }
2144 
2145 // ----------------------------------------------------------------------------
2146 // this wxWindowBase function is implemented here (in platform-specific file)
2147 // because it is static and so couldn't be made virtual
2148 // ----------------------------------------------------------------------------
2149 
DoFindFocus()2150 wxWindow *wxWindowBase::DoFindFocus()
2151 {
2152     // the cast is necessary when we compile in wxUniversal mode
2153     return (wxWindow *)g_focusWindow;
2154 }
2155 
2156 //-----------------------------------------------------------------------------
2157 // "realize" from m_widget
2158 //-----------------------------------------------------------------------------
2159 
2160 /* We cannot set colours and fonts before the widget has
2161    been realized, so we do this directly after realization. */
2162 
2163 extern "C" {
2164 static gint
gtk_window_realized_callback(GtkWidget * WXUNUSED (widget),wxWindow * win)2165 gtk_window_realized_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
2166 {
2167     DEBUG_MAIN_THREAD
2168 
2169     if (g_isIdle)
2170         wxapp_install_idle_handler();
2171 
2172     wxWindowCreateEvent event( win );
2173     event.SetEventObject( win );
2174     win->HandleWindowEvent( event );
2175 
2176     return FALSE;
2177 }
2178 }
2179 
2180 //-----------------------------------------------------------------------------
2181 // "size_allocate"
2182 //-----------------------------------------------------------------------------
2183 
2184 extern "C" {
2185 static
gtk_window_size_callback(GtkWidget * WXUNUSED (widget),GtkAllocation * WXUNUSED (alloc),wxWindow * win)2186 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2187                                GtkAllocation *WXUNUSED(alloc),
2188                                wxWindow *win )
2189 {
2190     if (g_isIdle)
2191         wxapp_install_idle_handler();
2192 
2193     if (!win->m_hasScrolling) return;
2194 
2195     int client_width = 0;
2196     int client_height = 0;
2197     win->GetClientSize( &client_width, &client_height );
2198     if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2199         return;
2200 
2201     win->m_oldClientWidth = client_width;
2202     win->m_oldClientHeight = client_height;
2203 
2204     if (!win->m_nativeSizeEvent)
2205     {
2206         wxSizeEvent event( win->GetSize(), win->GetId() );
2207         event.SetEventObject( win );
2208         win->HandleWindowEvent( event );
2209     }
2210 }
2211 }
2212 
2213 
2214 #ifdef HAVE_XIM
2215     #define WXUNUSED_UNLESS_XIM(param)  param
2216 #else
2217     #define WXUNUSED_UNLESS_XIM(param)  WXUNUSED(param)
2218 #endif
2219 
2220 /* Resize XIM window */
2221 
2222 extern "C" {
2223 static
gtk_wxwindow_size_callback(GtkWidget * WXUNUSED_UNLESS_XIM (widget),GtkAllocation * WXUNUSED (alloc),wxWindowGTK * WXUNUSED_UNLESS_XIM (win))2224 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2225                                  GtkAllocation* WXUNUSED(alloc),
2226                                  wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2227 {
2228     if (g_isIdle)
2229         wxapp_install_idle_handler();
2230 
2231 #ifdef HAVE_XIM
2232     if (!win->m_ic)
2233         return;
2234 
2235     if  (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2236     {
2237         gint width, height;
2238 
2239         gdk_window_get_size (widget->window, &width, &height);
2240         win->m_icattr->preedit_area.width = width;
2241         win->m_icattr->preedit_area.height = height;
2242         gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2243     }
2244 #endif // HAVE_XIM
2245 }
2246 }
2247 
2248 //-----------------------------------------------------------------------------
2249 // "realize" from m_wxwindow
2250 //-----------------------------------------------------------------------------
2251 
2252 /* Initialize XIM support */
2253 
2254 extern "C" {
2255 static gint
gtk_wxwindow_realized_callback(GtkWidget * WXUNUSED_UNLESS_XIM (widget),wxWindowGTK * WXUNUSED_UNLESS_XIM (win))2256 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2257                                 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2258 {
2259     if (g_isIdle)
2260         wxapp_install_idle_handler();
2261 
2262 #ifdef HAVE_XIM
2263     if (win->m_ic) return FALSE;
2264     if (!widget) return FALSE;
2265     if (!gdk_im_ready()) return FALSE;
2266 
2267     win->m_icattr = gdk_ic_attr_new();
2268     if (!win->m_icattr) return FALSE;
2269 
2270     gint width, height;
2271     GdkEventMask mask;
2272     GdkColormap *colormap;
2273     GdkICAttr *attr = win->m_icattr;
2274     unsigned attrmask = GDK_IC_ALL_REQ;
2275     GdkIMStyle style;
2276     GdkIMStyle supported_style = (GdkIMStyle)
2277                                   (GDK_IM_PREEDIT_NONE |
2278                                    GDK_IM_PREEDIT_NOTHING |
2279                                    GDK_IM_PREEDIT_POSITION |
2280                                    GDK_IM_STATUS_NONE |
2281                                    GDK_IM_STATUS_NOTHING);
2282 
2283     if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2284         supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2285 
2286     attr->style = style = gdk_im_decide_style (supported_style);
2287     attr->client_window = widget->window;
2288 
2289     if ((colormap = gtk_widget_get_colormap (widget)) !=
2290             gtk_widget_get_default_colormap ())
2291     {
2292         attrmask |= GDK_IC_PREEDIT_COLORMAP;
2293         attr->preedit_colormap = colormap;
2294     }
2295 
2296     attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2297     attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2298     attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2299     attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2300 
2301     switch (style & GDK_IM_PREEDIT_MASK)
2302     {
2303         case GDK_IM_PREEDIT_POSITION:
2304             if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2305             {
2306                 g_warning ("over-the-spot style requires fontset");
2307                 break;
2308             }
2309 
2310             gdk_window_get_size (widget->window, &width, &height);
2311 
2312             attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2313             attr->spot_location.x = 0;
2314             attr->spot_location.y = height;
2315             attr->preedit_area.x = 0;
2316             attr->preedit_area.y = 0;
2317             attr->preedit_area.width = width;
2318             attr->preedit_area.height = height;
2319             attr->preedit_fontset = widget->style->font;
2320 
2321             break;
2322     }
2323 
2324       win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2325 
2326       if (win->m_ic == NULL)
2327           g_warning ("Can't create input context.");
2328       else
2329       {
2330           mask = gdk_window_get_events (widget->window);
2331           mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2332           gdk_window_set_events (widget->window, mask);
2333 
2334           if (GTK_WIDGET_HAS_FOCUS(widget))
2335               gdk_im_begin (win->m_ic, widget->window);
2336       }
2337 #endif // HAVE_XIM
2338 
2339     return FALSE;
2340 }
2341 }
2342 
2343 //-----------------------------------------------------------------------------
2344 // InsertChild for wxWindowGTK.
2345 //-----------------------------------------------------------------------------
2346 
2347 /* Callback for wxWindowGTK. This very strange beast has to be used because
2348  * C++ has no virtual methods in a constructor. We have to emulate a
2349  * virtual function here as wxNotebook requires a different way to insert
2350  * a child in it. I had opted for creating a wxNotebookPage window class
2351  * which would have made this superfluous (such in the MDI window system),
2352  * but no-one was listening to me... */
2353 
wxInsertChildInWindow(wxWindowGTK * parent,wxWindowGTK * child)2354 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2355 {
2356     /* the window might have been scrolled already, do we
2357        have to adapt the position */
2358     GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2359     child->m_x += pizza->xoffset;
2360     child->m_y += pizza->yoffset;
2361 
2362     gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2363                      GTK_WIDGET(child->m_widget),
2364                      child->m_x,
2365                      child->m_y,
2366                      child->m_width,
2367                      child->m_height );
2368 }
2369 
2370 //-----------------------------------------------------------------------------
2371 // global functions
2372 //-----------------------------------------------------------------------------
2373 
wxGetActiveWindow()2374 wxWindow *wxGetActiveWindow()
2375 {
2376     return wxWindow::FindFocus();
2377 }
2378 
2379 
wxGetMouseState()2380 wxMouseState wxGetMouseState()
2381 {
2382     wxMouseState ms;
2383 
2384     gint x;
2385     gint y;
2386     GdkModifierType mask;
2387 
2388     gdk_window_get_pointer(NULL, &x, &y, &mask);
2389 
2390     ms.SetX(x);
2391     ms.SetY(y);
2392     ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
2393     ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
2394     ms.SetRightDown(mask & GDK_BUTTON3_MASK);
2395 
2396     ms.SetControlDown(mask & GDK_CONTROL_MASK);
2397     ms.SetShiftDown(mask & GDK_SHIFT_MASK);
2398     ms.SetAltDown(mask & GDK_MOD1_MASK);
2399     ms.SetMetaDown(mask & GDK_MOD2_MASK);
2400 
2401     return ms;
2402 }
2403 
2404 //-----------------------------------------------------------------------------
2405 // wxWindowGTK
2406 //-----------------------------------------------------------------------------
2407 
2408 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2409 // method
2410 #ifdef __WXUNIVERSAL__
2411     wxIMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase);
2412 #endif // __WXUNIVERSAL__
2413 
Init()2414 void wxWindowGTK::Init()
2415 {
2416     // GTK specific
2417     m_widget = NULL;
2418     m_wxwindow = NULL;
2419     m_focusWidget = NULL;
2420 
2421     // position/size
2422     m_x = 0;
2423     m_y = 0;
2424     m_width = 0;
2425     m_height = 0;
2426 
2427     m_sizeSet = false;
2428     m_hasVMT = false;
2429     m_needParent = true;
2430 
2431     m_noExpose = false;
2432     m_nativeSizeEvent = false;
2433 
2434     m_hasScrolling = false;
2435     m_isScrolling = false;
2436 
2437     m_hAdjust = NULL;
2438     m_vAdjust = NULL;
2439     m_oldHorizontalPos =
2440     m_oldVerticalPos = 0.0;
2441     m_oldClientWidth =
2442     m_oldClientHeight = 0;
2443 
2444     m_resizing = false;
2445 
2446     m_insertCallback = (wxInsertChildFunction) NULL;
2447 
2448     m_acceptsFocus = false;
2449     m_hasFocus = false;
2450 
2451     m_clipPaintRegion = false;
2452 
2453     m_needsStyleChange = false;
2454 
2455     m_cursor = *wxSTANDARD_CURSOR;
2456 
2457 #ifdef HAVE_XIM
2458     m_ic = NULL;
2459     m_icattr = NULL;
2460 #endif
2461 }
2462 
wxWindowGTK()2463 wxWindowGTK::wxWindowGTK()
2464 {
2465     Init();
2466 }
2467 
wxWindowGTK(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)2468 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2469                           wxWindowID id,
2470                           const wxPoint &pos,
2471                           const wxSize &size,
2472                           long style,
2473                           const wxString &name  )
2474 {
2475     Init();
2476 
2477     Create( parent, id, pos, size, style, name );
2478 }
2479 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)2480 bool wxWindowGTK::Create( wxWindow *parent,
2481                           wxWindowID id,
2482                           const wxPoint &pos,
2483                           const wxSize &size,
2484                           long style,
2485                           const wxString &name  )
2486 {
2487     // Get default border
2488     wxBorder border = GetBorder(style);
2489     style &= ~wxBORDER_MASK;
2490     style |= border;
2491 
2492     if (!PreCreation( parent, pos, size ) ||
2493         !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2494     {
2495         wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2496         return false;
2497     }
2498 
2499     m_insertCallback = wxInsertChildInWindow;
2500 
2501     m_widget = gtk_scrolled_window_new( NULL, NULL );
2502     GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2503 
2504     GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2505 
2506     GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2507     scroll_class->scrollbar_spacing = 0;
2508 
2509     gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2510 
2511     m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2512     m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2513 
2514     m_wxwindow = gtk_pizza_new();
2515 
2516 #ifndef __WXUNIVERSAL__
2517     GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2518 
2519     if (HasFlag(wxRAISED_BORDER))
2520     {
2521         gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2522     }
2523     else if (HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
2524     {
2525         gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2526     }
2527     else if (HasFlag(wxSIMPLE_BORDER))
2528     {
2529         gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2530     }
2531     else
2532     {
2533         gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2534     }
2535 #endif // __WXUNIVERSAL__
2536 
2537     gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2538 
2539     GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2540     m_acceptsFocus = true;
2541 
2542     // I _really_ don't want scrollbars in the beginning
2543     m_vAdjust->lower = 0.0;
2544     m_vAdjust->upper = 1.0;
2545     m_vAdjust->value = 0.0;
2546     m_vAdjust->step_increment = 1.0;
2547     m_vAdjust->page_increment = 1.0;
2548     m_vAdjust->page_size = 5.0;
2549     gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2550     m_hAdjust->lower = 0.0;
2551     m_hAdjust->upper = 1.0;
2552     m_hAdjust->value = 0.0;
2553     m_hAdjust->step_increment = 1.0;
2554     m_hAdjust->page_increment = 1.0;
2555     m_hAdjust->page_size = 5.0;
2556     gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2557 
2558     // these handlers block mouse events to any window during scrolling such as
2559     // motion events and prevent GTK and wxWidgets from fighting over where the
2560     // slider should be
2561 
2562     gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2563           (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2564 
2565     gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2566           (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2567 
2568     gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2569           (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2570 
2571     gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2572           (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2573 
2574     // these handlers get notified when screen updates are required either when
2575     // scrolling or when the window size (and therefore scrollbar configuration)
2576     // has changed
2577 
2578     gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2579           (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2580     gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2581           (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2582 
2583     gtk_widget_show( m_wxwindow );
2584 
2585     if (m_parent)
2586         m_parent->DoAddChild( this );
2587 
2588     m_focusWidget = m_wxwindow;
2589 
2590     PostCreation();
2591 
2592     return true;
2593 }
2594 
~wxWindowGTK()2595 wxWindowGTK::~wxWindowGTK()
2596 {
2597     SendDestroyEvent();
2598 
2599     if (g_focusWindow == this)
2600         g_focusWindow = NULL;
2601 
2602     if ( g_delayedFocus == this )
2603         g_delayedFocus = NULL;
2604 
2605     m_hasVMT = false;
2606 
2607     // destroy children before destroying this window itself
2608     DestroyChildren();
2609 
2610     // unhook focus handlers to prevent stray events being
2611     // propagated to this (soon to be) dead object
2612     if (m_focusWidget != NULL)
2613     {
2614         gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2615             (GtkSignalFunc) gtk_window_focus_in_callback, (gpointer) this );
2616         gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2617             (GtkSignalFunc) gtk_window_focus_out_callback, (gpointer) this );
2618     }
2619 
2620     if (m_widget)
2621         Show( false );
2622 
2623 #ifdef HAVE_XIM
2624     if (m_ic)
2625         gdk_ic_destroy (m_ic);
2626     if (m_icattr)
2627         gdk_ic_attr_destroy (m_icattr);
2628 #endif
2629 
2630     if (m_wxwindow)
2631     {
2632         gtk_widget_destroy( m_wxwindow );
2633         m_wxwindow = NULL;
2634     }
2635 
2636     if (m_widget)
2637     {
2638         gtk_widget_destroy( m_widget );
2639         m_widget = NULL;
2640     }
2641 }
2642 
PreCreation(wxWindowGTK * parent,const wxPoint & pos,const wxSize & size)2643 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos,  const wxSize &size )
2644 {
2645     wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
2646 
2647     // Use either the given size, or the default if -1 is given.
2648     // See wxWindowBase for these functions.
2649     m_width = WidthDefault(size.x) ;
2650     m_height = HeightDefault(size.y);
2651 
2652     m_x = (int)pos.x;
2653     m_y = (int)pos.y;
2654 
2655     return true;
2656 }
2657 
PostCreation()2658 void wxWindowGTK::PostCreation()
2659 {
2660     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2661 
2662     if (m_wxwindow)
2663     {
2664         if (!m_noExpose)
2665         {
2666             // these get reported to wxWidgets -> wxPaintEvent
2667 
2668             gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2669 
2670             gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2671                 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2672 
2673             gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2674                 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2675 
2676             if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2677             {
2678                 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2679                     GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2680             }
2681         }
2682 
2683         // these are called when the "sunken" or "raised" borders are drawn
2684         gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2685           GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2686 
2687         gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2688           GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2689     }
2690 
2691     // focus handling
2692 
2693     if (!GTK_IS_WINDOW(m_widget))
2694     {
2695         if (m_focusWidget == NULL)
2696             m_focusWidget = m_widget;
2697 
2698         gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2699             GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2700 
2701         gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2702             GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2703     }
2704 
2705     // connect to the various key and mouse handlers
2706 
2707     GtkWidget *connect_widget = GetConnectWidget();
2708 
2709     ConnectWidget( connect_widget );
2710 
2711     /* We cannot set colours, fonts and cursors before the widget has
2712        been realized, so we do this directly after realization */
2713     gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2714                             GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2715 
2716     if (m_wxwindow)
2717     {
2718         // Catch native resize events
2719         gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2720                             GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2721 
2722         // Initialize XIM support
2723         gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2724                             GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2725 
2726         // And resize XIM window
2727         gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2728                             GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2729     }
2730 
2731     if (GTK_IS_COMBO(m_widget))
2732     {
2733         GtkCombo *gcombo = GTK_COMBO(m_widget);
2734 
2735         gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
2736                             GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
2737                             (gpointer) this );
2738     }
2739     else
2740     {
2741         // This is needed if we want to add our windows into native
2742         // GTK controls, such as the toolbar. With this callback, the
2743         // toolbar gets to know the correct size (the one set by the
2744         // programmer). Sadly, it misbehaves for wxComboBox.
2745         gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2746                             GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2747                             (gpointer) this );
2748     }
2749 
2750     InheritAttributes();
2751 
2752     m_hasVMT = true;
2753 
2754     // unless the window was created initially hidden (i.e. Hide() had been
2755     // called before Create()), we should show it at GTK+ level as well
2756     if ( IsShown() )
2757         gtk_widget_show( m_widget );
2758 }
2759 
ConnectWidget(GtkWidget * widget)2760 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2761 {
2762     gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2763       GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2764 
2765     gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2766       GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2767 
2768     gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2769       GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2770 
2771     gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2772       GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2773 
2774     gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2775       GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2776 
2777     gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2778       GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2779 
2780     gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2781       GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2782 }
2783 
Destroy()2784 bool wxWindowGTK::Destroy()
2785 {
2786     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2787 
2788     m_hasVMT = false;
2789 
2790     return wxWindowBase::Destroy();
2791 }
2792 
DoMoveWindow(int x,int y,int width,int height)2793 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
2794 {
2795     gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2796 }
2797 
DoSetSize(int x,int y,int width,int height,int sizeFlags)2798 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2799 {
2800     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2801     wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
2802 
2803 /*
2804     printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2805 */
2806 
2807     if (m_resizing) return; /* I don't like recursions */
2808     m_resizing = true;
2809 
2810     int currentX, currentY;
2811     GetPosition(&currentX, &currentY);
2812     if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2813         x = currentX;
2814     if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2815         y = currentY;
2816     AdjustForParentClientOrigin(x, y, sizeFlags);
2817 
2818     if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2819     {
2820         /* don't set the size for children of wxNotebook, just take the values. */
2821         m_x = x;
2822         m_y = y;
2823         m_width = width;
2824         m_height = height;
2825     }
2826     else
2827     {
2828         GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2829         if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2830         {
2831             if (x != -1) m_x = x + pizza->xoffset;
2832             if (y != -1) m_y = y + pizza->yoffset;
2833         }
2834         else
2835         {
2836             m_x = x + pizza->xoffset;
2837             m_y = y + pizza->yoffset;
2838         }
2839 
2840         // calculate the best size if we should auto size the window
2841         if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
2842                 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
2843         {
2844             const wxSize sizeBest = GetBestSize();
2845             if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
2846                 width = sizeBest.x;
2847             if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
2848                 height = sizeBest.y;
2849         }
2850 
2851         if (width != -1)
2852             m_width = width;
2853         if (height != -1)
2854             m_height = height;
2855 
2856         int minWidth = GetMinWidth(),
2857             minHeight = GetMinHeight(),
2858             maxWidth = GetMaxWidth(),
2859             maxHeight = GetMaxHeight();
2860 
2861         if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
2862         if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2863         if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
2864         if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
2865 
2866         int left_border = 0;
2867         int right_border = 0;
2868         int top_border = 0;
2869         int bottom_border = 0;
2870 
2871         /* the default button has a border around it */
2872         if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2873         {
2874             left_border = 6;
2875             right_border = 6;
2876             top_border = 6;
2877             bottom_border = 5;
2878         }
2879 
2880         DoMoveWindow( m_x-top_border,
2881                       m_y-left_border,
2882                       m_width+left_border+right_border,
2883                       m_height+top_border+bottom_border );
2884     }
2885 
2886     if (m_hasScrolling)
2887     {
2888         /* Sometimes the client area changes size without the
2889            whole windows's size changing, but if the whole
2890            windows's size doesn't change, no wxSizeEvent will
2891            normally be sent. Here we add an extra test if
2892            the client test has been changed and this will
2893            be used then. */
2894         GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2895     }
2896 
2897 /*
2898     wxPrintf( "OnSize sent from " );
2899     if (GetClassInfo() && GetClassInfo()->GetClassName())
2900         wxPrintf( GetClassInfo()->GetClassName() );
2901     wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2902 */
2903 
2904     if (!m_nativeSizeEvent)
2905     {
2906         wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2907         event.SetEventObject( this );
2908         HandleWindowEvent( event );
2909     }
2910 
2911     m_resizing = false;
2912 }
2913 
OnInternalIdle()2914 void wxWindowGTK::OnInternalIdle()
2915 {
2916     // Update style if the window was not yet realized
2917     // and SetBackgroundStyle(wxBG_STYLE_PAINT) was called
2918     if (m_needsStyleChange)
2919     {
2920         SetBackgroundStyle(GetBackgroundStyle());
2921         m_needsStyleChange = false;
2922     }
2923 
2924     // Update invalidated regions.
2925     GtkUpdate();
2926 
2927     wxCursor cursor = m_cursor;
2928     if (g_globalCursor.IsOk()) cursor = g_globalCursor;
2929 
2930     if (cursor.IsOk())
2931     {
2932         /* I now set the cursor anew in every OnInternalIdle call
2933            as setting the cursor in a parent window also effects the
2934            windows above so that checking for the current cursor is
2935            not possible. */
2936 
2937         if (m_wxwindow)
2938         {
2939             GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2940             if (window)
2941                 gdk_window_set_cursor( window, cursor.GetCursor() );
2942 
2943             if (!g_globalCursor.IsOk())
2944                 cursor = *wxSTANDARD_CURSOR;
2945 
2946             window = m_widget->window;
2947             if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2948                 gdk_window_set_cursor( window, cursor.GetCursor() );
2949 
2950         }
2951         else if ( m_widget )
2952         {
2953             GdkWindow *window = m_widget->window;
2954             if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) )
2955                gdk_window_set_cursor( window, cursor.GetCursor() );
2956         }
2957     }
2958 
2959     wxWindowBase::OnInternalIdle();
2960 }
2961 
DoGetSize(int * width,int * height) const2962 void wxWindowGTK::DoGetSize( int *width, int *height ) const
2963 {
2964     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2965 
2966     if (width) (*width) = m_width;
2967     if (height) (*height) = m_height;
2968 }
2969 
DoSetClientSize(int width,int height)2970 void wxWindowGTK::DoSetClientSize( int width, int height )
2971 {
2972     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2973 
2974     if (!m_wxwindow)
2975     {
2976         SetSize( width, height );
2977     }
2978     else
2979     {
2980         int dw = 0;
2981         int dh = 0;
2982 
2983 #ifndef __WXUNIVERSAL__
2984         if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
2985         {
2986             /* when using GTK 1.2 we set the shadow border size to 2 */
2987             dw += 2 * 2;
2988             dh += 2 * 2;
2989         }
2990         if (HasFlag(wxSIMPLE_BORDER))
2991         {
2992             /* when using GTK 1.2 we set the simple border size to 1 */
2993             dw += 1 * 2;
2994             dh += 1 * 2;
2995         }
2996 #endif // __WXUNIVERSAL__
2997 
2998         if (m_hasScrolling)
2999         {
3000             GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3001 
3002             GtkRequisition vscroll_req;
3003             vscroll_req.width = 2;
3004             vscroll_req.height = 2;
3005             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3006                 (scroll_window->vscrollbar, &vscroll_req );
3007 
3008             GtkRequisition hscroll_req;
3009             hscroll_req.width = 2;
3010             hscroll_req.height = 2;
3011             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3012                 (scroll_window->hscrollbar, &hscroll_req );
3013 
3014             GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3015 
3016             if (scroll_window->vscrollbar_visible)
3017             {
3018                 dw += vscroll_req.width;
3019                 dw += scroll_class->scrollbar_spacing;
3020             }
3021 
3022             if (scroll_window->hscrollbar_visible)
3023             {
3024                 dh += hscroll_req.height;
3025                 dh += scroll_class->scrollbar_spacing;
3026             }
3027         }
3028 
3029        SetSize( width+dw, height+dh );
3030     }
3031 }
3032 
DoGetClientSize(int * width,int * height) const3033 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3034 {
3035     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3036 
3037     if (!m_wxwindow)
3038     {
3039         if (width) (*width) = m_width;
3040         if (height) (*height) = m_height;
3041     }
3042     else
3043     {
3044         int dw = 0;
3045         int dh = 0;
3046 
3047 #ifndef __WXUNIVERSAL__
3048         if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER) || HasFlag(wxBORDER_THEME))
3049         {
3050             /* when using GTK 1.2 we set the shadow border size to 2 */
3051             dw += 2 * 2;
3052             dh += 2 * 2;
3053         }
3054         if (HasFlag(wxSIMPLE_BORDER))
3055         {
3056             /* when using GTK 1.2 we set the simple border size to 1 */
3057             dw += 1 * 2;
3058             dh += 1 * 2;
3059         }
3060 #endif // __WXUNIVERSAL__
3061 
3062         if (m_hasScrolling)
3063         {
3064             GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3065 
3066             GtkRequisition vscroll_req;
3067             vscroll_req.width = 2;
3068             vscroll_req.height = 2;
3069             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3070                 (scroll_window->vscrollbar, &vscroll_req );
3071 
3072             GtkRequisition hscroll_req;
3073             hscroll_req.width = 2;
3074             hscroll_req.height = 2;
3075             (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3076                 (scroll_window->hscrollbar, &hscroll_req );
3077 
3078             GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3079 
3080             if (scroll_window->vscrollbar_visible)
3081             {
3082                 dw += vscroll_req.width;
3083                 dw += scroll_class->scrollbar_spacing;
3084             }
3085 
3086             if (scroll_window->hscrollbar_visible)
3087             {
3088                 dh += hscroll_req.height;
3089                 dh += scroll_class->scrollbar_spacing;
3090             }
3091         }
3092 
3093         if (width) (*width) = m_width - dw;
3094         if (height) (*height) = m_height - dh;
3095     }
3096 
3097 /*
3098     printf( "GetClientSize, name %s ", GetName().c_str() );
3099     if (width) printf( " width = %d", (*width) );
3100     if (height) printf( " height = %d", (*height) );
3101     printf( "\n" );
3102 */
3103 }
3104 
DoGetPosition(int * x,int * y) const3105 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3106 {
3107     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3108 
3109     int dx = 0;
3110     int dy = 0;
3111     if (m_parent && m_parent->m_wxwindow)
3112     {
3113         GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3114         dx = pizza->xoffset;
3115         dy = pizza->yoffset;
3116     }
3117 
3118     if (x) (*x) = m_x - dx;
3119     if (y) (*y) = m_y - dy;
3120 }
3121 
DoClientToScreen(int * x,int * y) const3122 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3123 {
3124     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3125 
3126     if (!m_widget->window) return;
3127 
3128     GdkWindow *source = NULL;
3129     if (m_wxwindow)
3130         source = GTK_PIZZA(m_wxwindow)->bin_window;
3131     else
3132         source = m_widget->window;
3133 
3134     int org_x = 0;
3135     int org_y = 0;
3136     gdk_window_get_origin( source, &org_x, &org_y );
3137 
3138     if (!m_wxwindow)
3139     {
3140         if (GTK_WIDGET_NO_WINDOW (m_widget))
3141         {
3142             org_x += m_widget->allocation.x;
3143             org_y += m_widget->allocation.y;
3144         }
3145     }
3146 
3147     if (x) *x += org_x;
3148     if (y) *y += org_y;
3149 }
3150 
DoScreenToClient(int * x,int * y) const3151 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3152 {
3153     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3154 
3155     if (!m_widget->window) return;
3156 
3157     GdkWindow *source = NULL;
3158     if (m_wxwindow)
3159         source = GTK_PIZZA(m_wxwindow)->bin_window;
3160     else
3161         source = m_widget->window;
3162 
3163     int org_x = 0;
3164     int org_y = 0;
3165     gdk_window_get_origin( source, &org_x, &org_y );
3166 
3167     if (!m_wxwindow)
3168     {
3169         if (GTK_WIDGET_NO_WINDOW (m_widget))
3170         {
3171             org_x += m_widget->allocation.x;
3172             org_y += m_widget->allocation.y;
3173         }
3174     }
3175 
3176     if (x) *x -= org_x;
3177     if (y) *y -= org_y;
3178 }
3179 
Show(bool show)3180 bool wxWindowGTK::Show( bool show )
3181 {
3182     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3183 
3184     if (!wxWindowBase::Show(show))
3185     {
3186         // nothing to do
3187         return false;
3188     }
3189 
3190     if (show)
3191         gtk_widget_show( m_widget );
3192     else
3193         gtk_widget_hide( m_widget );
3194 
3195     wxShowEvent eventShow(GetId(), show);
3196     eventShow.SetEventObject(this);
3197 
3198     HandleWindowEvent(eventShow);
3199 
3200     return true;
3201 }
3202 
DoEnable(bool enable)3203 void wxWindowGTK::DoEnable( bool enable )
3204 {
3205     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3206 
3207     gtk_widget_set_sensitive( m_widget, enable );
3208     if ( m_wxwindow )
3209         gtk_widget_set_sensitive( m_wxwindow, enable );
3210 }
3211 
GetCharHeight() const3212 int wxWindowGTK::GetCharHeight() const
3213 {
3214     wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3215 
3216     wxFont font = GetFont();
3217     wxCHECK_MSG( font.IsOk(), 12, wxT("invalid font") );
3218 
3219     GdkFont *gfont = font.GetInternalFont( 1.0 );
3220 
3221     return gfont->ascent + gfont->descent;
3222 }
3223 
GetCharWidth() const3224 int wxWindowGTK::GetCharWidth() const
3225 {
3226     wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3227 
3228     wxFont font = GetFont();
3229     wxCHECK_MSG( font.IsOk(), 8, wxT("invalid font") );
3230 
3231     GdkFont *gfont = font.GetInternalFont( 1.0 );
3232 
3233     return gdk_string_width( gfont, "g" );
3234 }
3235 
DoGetTextExtent(const wxString & string,int * x,int * y,int * descent,int * externalLeading,const wxFont * theFont) const3236 void wxWindowGTK::DoGetTextExtent(const wxString& string,
3237                                   int *x,
3238                                   int *y,
3239                                   int *descent,
3240                                   int *externalLeading,
3241                                   const wxFont *theFont) const
3242 {
3243     wxFont fontToUse = theFont ? *theFont : GetFont();
3244 
3245     wxCHECK_RET( fontToUse.IsOk(), wxT("invalid font") );
3246 
3247     if (string.empty())
3248     {
3249         if (x) (*x) = 0;
3250         if (y) (*y) = 0;
3251         return;
3252     }
3253 
3254     GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3255     if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3256     if (y) (*y) = font->ascent + font->descent;
3257     if (descent) (*descent) = font->descent;
3258     if (externalLeading) (*externalLeading) = 0;  // ??
3259 }
3260 
SetFocus()3261 void wxWindowGTK::SetFocus()
3262 {
3263     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3264     if ( m_hasFocus )
3265     {
3266         // don't do anything if we already have focus
3267         return;
3268     }
3269 
3270     if (m_wxwindow)
3271     {
3272         if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3273         {
3274             gtk_widget_grab_focus (m_wxwindow);
3275         }
3276     }
3277     else if (m_widget)
3278     {
3279         if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3280         {
3281 
3282             if (!GTK_WIDGET_REALIZED(m_widget))
3283             {
3284                 // we can't set the focus to the widget now so we remember that
3285                 // it should be focused and will do it later, during the idle
3286                 // time, as soon as we can
3287                 wxLogTrace(TRACE_FOCUS,
3288                            wxT("Delaying setting focus to %s(%s)"),
3289                            GetClassInfo()->GetClassName(), GetLabel().c_str());
3290 
3291                 g_delayedFocus = this;
3292             }
3293             else
3294             {
3295                 wxLogTrace(TRACE_FOCUS,
3296                            wxT("Setting focus to %s(%s)"),
3297                            GetClassInfo()->GetClassName(), GetLabel().c_str());
3298 
3299                 gtk_widget_grab_focus (m_widget);
3300             }
3301         }
3302         else
3303         if (GTK_IS_CONTAINER(m_widget))
3304         {
3305             gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3306         }
3307         else
3308         {
3309            wxLogTrace(TRACE_FOCUS,
3310                       wxT("Can't set focus to %s(%s)"),
3311                       GetClassInfo()->GetClassName(), GetLabel().c_str());
3312         }
3313     }
3314 }
3315 
AcceptsFocus() const3316 bool wxWindowGTK::AcceptsFocus() const
3317 {
3318     return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3319 }
3320 
Reparent(wxWindowBase * newParentBase)3321 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3322 {
3323     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3324 
3325     wxWindowGTK *oldParent = m_parent,
3326              *newParent = (wxWindowGTK *)newParentBase;
3327 
3328     wxASSERT( GTK_IS_WIDGET(m_widget) );
3329 
3330     if ( !wxWindowBase::Reparent(newParent) )
3331         return false;
3332 
3333     wxASSERT( GTK_IS_WIDGET(m_widget) );
3334 
3335     /* prevent GTK from deleting the widget arbitrarily */
3336     gtk_widget_ref( m_widget );
3337 
3338     if (oldParent)
3339     {
3340         gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3341     }
3342 
3343     wxASSERT( GTK_IS_WIDGET(m_widget) );
3344 
3345     if (newParent)
3346     {
3347         /* insert GTK representation */
3348         (*(newParent->m_insertCallback))(newParent, this);
3349     }
3350 
3351     /* reverse: prevent GTK from deleting the widget arbitrarily */
3352     gtk_widget_unref( m_widget );
3353 
3354     return true;
3355 }
3356 
DoAddChild(wxWindowGTK * child)3357 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3358 {
3359     wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3360 
3361     wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3362 
3363     wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3364 
3365     /* add to list */
3366     AddChild( child );
3367 
3368     /* insert GTK representation */
3369     (*m_insertCallback)(this, child);
3370 }
3371 
Raise()3372 void wxWindowGTK::Raise()
3373 {
3374     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3375 
3376     if (m_wxwindow && m_wxwindow->window)
3377     {
3378         gdk_window_raise( m_wxwindow->window );
3379     }
3380     else if (m_widget->window)
3381     {
3382         gdk_window_raise( m_widget->window );
3383     }
3384 }
3385 
Lower()3386 void wxWindowGTK::Lower()
3387 {
3388     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3389 
3390     if (m_wxwindow && m_wxwindow->window)
3391     {
3392         gdk_window_lower( m_wxwindow->window );
3393     }
3394     else if (m_widget->window)
3395     {
3396         gdk_window_lower( m_widget->window );
3397     }
3398 }
3399 
SetCursor(const wxCursor & cursor)3400 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3401 {
3402     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3403 
3404     if ( cursor.IsSameAs(m_cursor) )
3405        return false;
3406 
3407     if (g_isIdle)
3408         wxapp_install_idle_handler();
3409 
3410     return wxWindowBase::SetCursor( cursor.IsOk() ? cursor
3411                                                   : *wxSTANDARD_CURSOR );
3412 }
3413 
WarpPointer(int x,int y)3414 void wxWindowGTK::WarpPointer( int x, int y )
3415 {
3416     wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3417 
3418     // We provide this function ourselves as it is
3419     // missing in GDK (top of this file).
3420 
3421     GdkWindow *window = NULL;
3422     if (m_wxwindow)
3423         window = GTK_PIZZA(m_wxwindow)->bin_window;
3424     else
3425         window = GetConnectWidget()->window;
3426 
3427     if (window)
3428         gdk_window_warp_pointer( window, x, y );
3429 }
3430 
3431 
Refresh(bool eraseBackground,const wxRect * rect)3432 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3433 {
3434     if (!m_widget)
3435         return;
3436     if (!m_widget->window)
3437         return;
3438 
3439     if (g_isIdle)
3440         wxapp_install_idle_handler();
3441 
3442     wxRect myRect;
3443     if (m_wxwindow && rect)
3444     {
3445         myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3446                                m_wxwindow->allocation.height));
3447         if ( myRect.Intersect(*rect).IsEmpty() )
3448         {
3449             // nothing to do, rectangle is empty
3450             return;
3451         }
3452 
3453         rect = &myRect;
3454     }
3455 
3456     // schedule the area for later updating in GtkUpdate()
3457     if (eraseBackground && m_wxwindow && m_wxwindow->window)
3458     {
3459         if (rect)
3460         {
3461             m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3462         }
3463         else
3464         {
3465             m_clearRegion.Clear();
3466             m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3467         }
3468     }
3469 
3470     if (rect)
3471     {
3472         if (m_wxwindow)
3473         {
3474             m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3475         }
3476         else
3477         {
3478             GdkRectangle gdk_rect;
3479             gdk_rect.x = rect->x;
3480             gdk_rect.y = rect->y;
3481             gdk_rect.width = rect->width;
3482             gdk_rect.height = rect->height;
3483             gtk_widget_draw( m_widget, &gdk_rect );
3484         }
3485     }
3486     else
3487     {
3488         if (m_wxwindow)
3489         {
3490             m_updateRegion.Clear();
3491             m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3492         }
3493         else
3494         {
3495             gtk_widget_draw( m_widget, NULL );
3496         }
3497     }
3498 }
3499 
Update()3500 void wxWindowGTK::Update()
3501 {
3502     GtkUpdate();
3503 
3504     // when we call Update() we really want to update the window immediately on
3505     // screen, even if it means flushing the entire queue and hence slowing down
3506     // everything -- but it should still be done, it's just that Update() should
3507     // be called very rarely
3508     gdk_flush();
3509 }
3510 
GtkUpdate()3511 void wxWindowGTK::GtkUpdate()
3512 {
3513     if (!m_updateRegion.IsEmpty())
3514         GtkSendPaintEvents();
3515 
3516     // for consistency with other platforms (and also because it's convenient
3517     // to be able to update an entire TLW by calling Update() only once), we
3518     // should also update all our children here
3519     for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3520           node;
3521           node = node->GetNext() )
3522     {
3523         node->GetData()->GtkUpdate();
3524     }
3525 }
3526 
GtkSendPaintEvents()3527 void wxWindowGTK::GtkSendPaintEvents()
3528 {
3529     if (!m_wxwindow)
3530     {
3531         m_clearRegion.Clear();
3532         m_updateRegion.Clear();
3533         return;
3534     }
3535 
3536     // Clip to paint region in wxClientDC
3537     m_clipPaintRegion = true;
3538 
3539     // widget to draw on
3540     GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
3541 
3542     if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
3543     {
3544         // find ancestor from which to steal background
3545         wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
3546         if (!parent)
3547             parent = (wxWindow*)this;
3548 
3549         if (GTK_WIDGET_MAPPED(parent->m_widget))
3550         {
3551             wxRegionIterator upd( m_updateRegion );
3552             while (upd)
3553             {
3554                 GdkRectangle rect;
3555                 rect.x = upd.GetX();
3556                 rect.y = upd.GetY();
3557                 rect.width = upd.GetWidth();
3558                 rect.height = upd.GetHeight();
3559 
3560                 gtk_paint_flat_box( parent->m_widget->style,
3561                             pizza->bin_window,
3562                             (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
3563                             GTK_SHADOW_NONE,
3564                             &rect,
3565                             parent->m_widget,
3566                             (char *)"base",
3567                             0, 0, -1, -1 );
3568 
3569                 ++upd;
3570             }
3571         }
3572     }
3573     else // Always send an erase event under GTK 1.2
3574     {
3575         wxWindowDC dc( (wxWindow*)this );
3576         dc.SetDeviceClippingRegion( m_clearRegion.IsEmpty() ? m_updateRegion
3577                                                             : m_clearRegion );
3578 
3579         wxEraseEvent erase_event( GetId(), &dc );
3580         erase_event.SetEventObject( this );
3581 
3582         if (!HandleWindowEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_PAINT)
3583         {
3584             if (!g_eraseGC)
3585             {
3586                 g_eraseGC = gdk_gc_new( pizza->bin_window );
3587                 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
3588             }
3589             gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
3590 
3591             wxRegionIterator upd( m_clearRegion );
3592             while (upd)
3593             {
3594                 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
3595                                     upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
3596                 upd ++;
3597             }
3598         }
3599         m_clearRegion.Clear();
3600     }
3601 
3602     wxNcPaintEvent nc_paint_event( this );
3603     HandleWindowEvent( nc_paint_event );
3604 
3605     wxPaintEvent paint_event( this );
3606     HandleWindowEvent( paint_event );
3607 
3608     m_clipPaintRegion = false;
3609 
3610 #if !defined(__WXUNIVERSAL__)
3611     // The following code will result in all window-less widgets
3612     // being redrawn because the wxWidgets class is allowed to
3613     // paint over the window-less widgets.
3614 
3615     GList *children = pizza->children;
3616     while (children)
3617     {
3618         GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3619         children = children->next;
3620 
3621         if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3622             GTK_WIDGET_DRAWABLE (child->widget))
3623         {
3624             // Get intersection of widget area and update region
3625             wxRegion region( m_updateRegion );
3626 
3627             GdkEventExpose gdk_event;
3628             gdk_event.type = GDK_EXPOSE;
3629             gdk_event.window = pizza->bin_window;
3630             gdk_event.count = 0;
3631             gdk_event.send_event = TRUE;
3632 
3633             wxRegionIterator upd( m_updateRegion );
3634             while (upd)
3635             {
3636                 GdkRectangle rect;
3637                 rect.x = upd.GetX();
3638                 rect.y = upd.GetY();
3639                 rect.width = upd.GetWidth();
3640                 rect.height = upd.GetHeight();
3641 
3642                 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3643                 {
3644                     gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3645                 }
3646 
3647                 upd ++;
3648             }
3649         }
3650     }
3651 #endif // native GTK 1
3652 
3653     m_updateRegion.Clear();
3654 }
3655 
ClearBackground()3656 void wxWindowGTK::ClearBackground()
3657 {
3658     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3659 
3660     if (m_wxwindow && m_wxwindow->window)
3661     {
3662         m_clearRegion.Clear();
3663         wxSize size( GetClientSize() );
3664         m_clearRegion.Union( 0,0,size.x,size.y );
3665 
3666         // Better do this in idle?
3667         GtkUpdate();
3668     }
3669 }
3670 
3671 #if wxUSE_TOOLTIPS
DoSetToolTip(wxToolTip * tip)3672 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
3673 {
3674     wxWindowBase::DoSetToolTip(tip);
3675 
3676     if (m_tooltip)
3677         m_tooltip->Apply( (wxWindow *)this );
3678 }
3679 
ApplyToolTip(GtkTooltips * tips,const wxChar * tip)3680 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3681 {
3682     wxString tmp( tip );
3683     gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), NULL );
3684 }
3685 #endif // wxUSE_TOOLTIPS
3686 
SetBackgroundColour(const wxColour & colour)3687 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
3688 {
3689     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3690 
3691     if (!wxWindowBase::SetBackgroundColour(colour))
3692         return false;
3693 
3694     if (colour.IsOk())
3695     {
3696         // We need the pixel value e.g. for background clearing.
3697         m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
3698     }
3699 
3700     // apply style change (forceStyle=true so that new style is applied
3701     // even if the bg colour changed from valid to wxNullColour)
3702     if (GetBackgroundStyle() != wxBG_STYLE_PAINT)
3703         ApplyWidgetStyle(true);
3704 
3705     return true;
3706 }
3707 
SetForegroundColour(const wxColour & colour)3708 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
3709 {
3710     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3711 
3712     if (!wxWindowBase::SetForegroundColour(colour))
3713     {
3714         return false;
3715     }
3716 
3717     if (colour.IsOk())
3718     {
3719         // We need the pixel value e.g. for background clearing.
3720         m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
3721     }
3722 
3723     // apply style change (forceStyle=true so that new style is applied
3724     // even if the bg colour changed from valid to wxNullColour):
3725     ApplyWidgetStyle(true);
3726 
3727     return true;
3728 }
3729 
CreateWidgetStyle(bool forceStyle)3730 GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
3731 {
3732     // do we need to apply any changes at all?
3733     if ( !forceStyle &&
3734          !m_font.IsOk() &&
3735          !m_foregroundColour.IsOk() && !m_backgroundColour.IsOk() )
3736     {
3737         return NULL;
3738     }
3739 
3740     GtkRcStyle *style = gtk_rc_style_new();
3741 
3742     if ( m_font.IsOk() )
3743     {
3744         wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
3745         style->fontset_name = g_strdup(xfontname.c_str());
3746     }
3747 
3748     if ( m_foregroundColour.IsOk() )
3749     {
3750         GdkColor *fg = m_foregroundColour.GetColor();
3751 
3752         style->fg[GTK_STATE_NORMAL] = *fg;
3753         style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
3754 
3755         style->fg[GTK_STATE_PRELIGHT] = *fg;
3756         style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
3757 
3758         style->fg[GTK_STATE_ACTIVE] = *fg;
3759         style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
3760     }
3761 
3762     if ( m_backgroundColour.IsOk() )
3763     {
3764         GdkColor *bg = m_backgroundColour.GetColor();
3765 
3766         style->bg[GTK_STATE_NORMAL] = *bg;
3767         style->base[GTK_STATE_NORMAL] = *bg;
3768         style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
3769             (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
3770 
3771         style->bg[GTK_STATE_PRELIGHT] = *bg;
3772         style->base[GTK_STATE_PRELIGHT] = *bg;
3773         style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
3774             (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
3775 
3776         style->bg[GTK_STATE_ACTIVE] = *bg;
3777         style->base[GTK_STATE_ACTIVE] = *bg;
3778         style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
3779             (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
3780 
3781         style->bg[GTK_STATE_INSENSITIVE] = *bg;
3782         style->base[GTK_STATE_INSENSITIVE] = *bg;
3783         style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
3784             (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
3785     }
3786 
3787     return style;
3788 }
3789 
ApplyWidgetStyle(bool forceStyle)3790 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
3791 {
3792     GtkRcStyle *style = CreateWidgetStyle(forceStyle);
3793     if ( style )
3794     {
3795         DoApplyWidgetStyle(style);
3796         gtk_rc_style_unref(style);
3797     }
3798 
3799     // Style change may affect GTK+'s size calculation:
3800     InvalidateBestSize();
3801 }
3802 
DoApplyWidgetStyle(GtkRcStyle * style)3803 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
3804 {
3805     if (m_wxwindow)
3806         gtk_widget_modify_style(m_wxwindow, style);
3807     else
3808         gtk_widget_modify_style(m_widget, style);
3809 }
3810 
SetBackgroundStyle(wxBackgroundStyle style)3811 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
3812 {
3813     wxWindowBase::SetBackgroundStyle(style);
3814 
3815     if (style == wxBG_STYLE_PAINT)
3816     {
3817         GdkWindow *window = NULL;
3818         if (m_wxwindow)
3819             window = GTK_PIZZA(m_wxwindow)->bin_window;
3820         else
3821             window = GetConnectWidget()->window;
3822 
3823         if (window)
3824         {
3825             // Make sure GDK/X11 doesn't refresh the window
3826             // automatically.
3827             gdk_window_set_back_pixmap( window, None, False );
3828 #ifdef __X__
3829             Display* display = GDK_WINDOW_DISPLAY(window);
3830             XFlush(display);
3831 #endif
3832             m_needsStyleChange = false;
3833         }
3834         else
3835             // Do in OnIdle, because the window is not yet available
3836             m_needsStyleChange = true;
3837 
3838         // Don't apply widget style, or we get a grey background
3839     }
3840     else
3841     {
3842         // apply style change (forceStyle=true so that new style is applied
3843         // even if the bg colour changed from valid to wxNullColour):
3844         ApplyWidgetStyle(true);
3845     }
3846     return true;
3847 }
3848 
3849 #if wxUSE_DRAG_AND_DROP
3850 
SetDropTarget(wxDropTarget * dropTarget)3851 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
3852 {
3853     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3854 
3855     GtkWidget *dnd_widget = GetConnectWidget();
3856 
3857     if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3858 
3859     if (m_dropTarget) delete m_dropTarget;
3860     m_dropTarget = dropTarget;
3861 
3862     if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3863 }
3864 
3865 #endif // wxUSE_DRAG_AND_DROP
3866 
GetConnectWidget()3867 GtkWidget* wxWindowGTK::GetConnectWidget()
3868 {
3869     GtkWidget *connect_widget = m_widget;
3870     if (m_wxwindow) connect_widget = m_wxwindow;
3871 
3872     return connect_widget;
3873 }
3874 
IsOwnGtkWindow(GdkWindow * window)3875 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
3876 {
3877     if (m_wxwindow)
3878         return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3879 
3880     return (window == m_widget->window);
3881 }
3882 
SetFont(const wxFont & font)3883 bool wxWindowGTK::SetFont( const wxFont &font )
3884 {
3885     wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
3886 
3887     if (!wxWindowBase::SetFont(font))
3888         return false;
3889 
3890     // apply style change (forceStyle=true so that new style is applied
3891     // even if the font changed from valid to wxNullFont):
3892     ApplyWidgetStyle(true);
3893 
3894     return true;
3895 }
3896 
DoCaptureMouse()3897 void wxWindowGTK::DoCaptureMouse()
3898 {
3899     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3900 
3901     GdkWindow *window = NULL;
3902     if (m_wxwindow)
3903         window = GTK_PIZZA(m_wxwindow)->bin_window;
3904     else
3905         window = GetConnectWidget()->window;
3906 
3907     wxCHECK_RET( window, wxT("CaptureMouse() failed") );
3908 
3909     const wxCursor* cursor = &m_cursor;
3910     if (!cursor->IsOk())
3911         cursor = wxSTANDARD_CURSOR;
3912 
3913     gdk_pointer_grab( window, FALSE,
3914                       (GdkEventMask)
3915                          (GDK_BUTTON_PRESS_MASK |
3916                           GDK_BUTTON_RELEASE_MASK |
3917                           GDK_POINTER_MOTION_HINT_MASK |
3918                           GDK_POINTER_MOTION_MASK),
3919                       NULL,
3920                       cursor->GetCursor(),
3921                       (guint32)GDK_CURRENT_TIME );
3922     g_captureWindow = this;
3923     g_captureWindowHasMouse = true;
3924 }
3925 
DoReleaseMouse()3926 void wxWindowGTK::DoReleaseMouse()
3927 {
3928     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3929 
3930     wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
3931 
3932     g_captureWindow = NULL;
3933 
3934     GdkWindow *window = NULL;
3935     if (m_wxwindow)
3936         window = GTK_PIZZA(m_wxwindow)->bin_window;
3937     else
3938         window = GetConnectWidget()->window;
3939 
3940     if (!window)
3941         return;
3942 
3943     gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3944 }
3945 
3946 /* static */
GetCapture()3947 wxWindow *wxWindowBase::GetCapture()
3948 {
3949     return (wxWindow *)g_captureWindow;
3950 }
3951 
IsRetained() const3952 bool wxWindowGTK::IsRetained() const
3953 {
3954     return false;
3955 }
3956 
SetScrollbar(int orient,int pos,int thumbVisible,int range,bool refresh)3957 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
3958       int range, bool refresh )
3959 {
3960     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3961 
3962     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3963 
3964     m_hasScrolling = true;
3965 
3966     if (orient == wxHORIZONTAL)
3967     {
3968         float fpos = (float)pos;
3969         float frange = (float)range;
3970         float fthumb = (float)thumbVisible;
3971         if (fpos > frange-fthumb) fpos = frange-fthumb;
3972         if (fpos < 0.0) fpos = 0.0;
3973 
3974         if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3975             (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3976         {
3977             SetScrollPos( orient, pos, refresh );
3978             return;
3979         }
3980 
3981         m_oldHorizontalPos = fpos;
3982 
3983         m_hAdjust->lower = 0.0;
3984         m_hAdjust->upper = frange;
3985         m_hAdjust->value = fpos;
3986         m_hAdjust->step_increment = 1.0;
3987         m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3988         m_hAdjust->page_size = fthumb;
3989     }
3990     else
3991     {
3992         float fpos = (float)pos;
3993         float frange = (float)range;
3994         float fthumb = (float)thumbVisible;
3995         if (fpos > frange-fthumb) fpos = frange-fthumb;
3996         if (fpos < 0.0) fpos = 0.0;
3997 
3998         if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3999             (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4000         {
4001             SetScrollPos( orient, pos, refresh );
4002             return;
4003         }
4004 
4005         m_oldVerticalPos = fpos;
4006 
4007         m_vAdjust->lower = 0.0;
4008         m_vAdjust->upper = frange;
4009         m_vAdjust->value = fpos;
4010         m_vAdjust->step_increment = 1.0;
4011         m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4012         m_vAdjust->page_size = fthumb;
4013     }
4014 
4015     if (orient == wxHORIZONTAL)
4016         gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4017     else
4018         gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4019 }
4020 
GtkUpdateScrollbar(int orient)4021 void wxWindowGTK::GtkUpdateScrollbar(int orient)
4022 {
4023     GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
4024     GtkSignalFunc fn = orient == wxHORIZONTAL
4025                         ? (GtkSignalFunc)gtk_window_hscroll_callback
4026                         : (GtkSignalFunc)gtk_window_vscroll_callback;
4027 
4028     gtk_signal_disconnect_by_func(GTK_OBJECT(adj), fn, (gpointer)this);
4029     gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
4030     gtk_signal_connect(GTK_OBJECT(adj), "value_changed", fn, (gpointer)this);
4031 }
4032 
SetScrollPos(int orient,int pos,bool WXUNUSED (refresh))4033 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4034 {
4035     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4036     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4037 
4038     GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
4039 
4040     float fpos = (float)pos;
4041     if (fpos > adj->upper - adj->page_size)
4042         fpos = adj->upper - adj->page_size;
4043     if (fpos < 0.0)
4044         fpos = 0.0;
4045     *(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos;
4046 
4047     if (fabs(fpos-adj->value) < 0.2)
4048         return;
4049     adj->value = fpos;
4050 
4051     if ( m_wxwindow->window )
4052     {
4053     }
4054 }
4055 
GetScrollThumb(int orient) const4056 int wxWindowGTK::GetScrollThumb( int orient ) const
4057 {
4058     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4059 
4060     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4061 
4062     if (orient == wxHORIZONTAL)
4063         return (int)(m_hAdjust->page_size+0.5);
4064     else
4065         return (int)(m_vAdjust->page_size+0.5);
4066 }
4067 
GetScrollPos(int orient) const4068 int wxWindowGTK::GetScrollPos( int orient ) const
4069 {
4070     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4071 
4072     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4073 
4074     if (orient == wxHORIZONTAL)
4075         return (int)(m_hAdjust->value+0.5);
4076     else
4077         return (int)(m_vAdjust->value+0.5);
4078 }
4079 
GetScrollRange(int orient) const4080 int wxWindowGTK::GetScrollRange( int orient ) const
4081 {
4082     wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4083 
4084     wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4085 
4086     if (orient == wxHORIZONTAL)
4087         return (int)(m_hAdjust->upper+0.5);
4088     else
4089         return (int)(m_vAdjust->upper+0.5);
4090 }
4091 
ScrollWindow(int dx,int dy,const wxRect * WXUNUSED (rect))4092 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4093 {
4094     wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4095 
4096     wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4097 
4098     // No scrolling requested.
4099     if ((dx == 0) && (dy == 0)) return;
4100 
4101     if (!m_updateRegion.IsEmpty())
4102     {
4103         m_updateRegion.Offset( dx, dy );
4104 
4105         int cw = 0;
4106         int ch = 0;
4107         GetClientSize( &cw, &ch );
4108         m_updateRegion.Intersect( 0, 0, cw, ch );
4109     }
4110 
4111     if (!m_clearRegion.IsEmpty())
4112     {
4113         m_clearRegion.Offset( dx, dy );
4114 
4115         int cw = 0;
4116         int ch = 0;
4117         GetClientSize( &cw, &ch );
4118         m_clearRegion.Intersect( 0, 0, cw, ch );
4119     }
4120 
4121     m_clipPaintRegion = true;
4122 
4123     gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4124 
4125     m_clipPaintRegion = false;
4126 }
4127 
SetWindowStyleFlag(long style)4128 void wxWindowGTK::SetWindowStyleFlag( long style )
4129 {
4130     // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4131     wxWindowBase::SetWindowStyleFlag(style);
4132 }
4133 
4134 // Find the wxWindow at the current mouse position, also returning the mouse
4135 // position.
wxFindWindowAtPointer(wxPoint & pt)4136 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4137 {
4138     pt = wxGetMousePosition();
4139     wxWindow* found = wxFindWindowAtPoint(pt);
4140     return found;
4141 }
4142 
4143 // Get the current mouse position.
wxGetMousePosition()4144 wxPoint wxGetMousePosition()
4145 {
4146   /* This crashes when used within wxHelpContext,
4147      so we have to use the X-specific implementation below.
4148     gint x, y;
4149     GdkModifierType *mask;
4150     (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4151 
4152     return wxPoint(x, y);
4153   */
4154 
4155     int x, y;
4156     GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4157 
4158     Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4159     Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4160     Window rootReturn, childReturn;
4161     int rootX, rootY, winX, winY;
4162     unsigned int maskReturn;
4163 
4164     XQueryPointer (display,
4165            rootWindow,
4166            &rootReturn,
4167                    &childReturn,
4168                    &rootX, &rootY, &winX, &winY, &maskReturn);
4169     return wxPoint(rootX, rootY);
4170 
4171 }
4172 
4173 // Needed for implementing e.g. combobox on wxGTK within a modal dialog.
wxAddGrab(wxWindow * window)4174 void wxAddGrab(wxWindow* window)
4175 {
4176     gtk_grab_add( (GtkWidget*) window->GetHandle() );
4177 }
4178 
wxRemoveGrab(wxWindow * window)4179 void wxRemoveGrab(wxWindow* window)
4180 {
4181     gtk_grab_remove( (GtkWidget*) window->GetHandle() );
4182 }
4183 
4184 // ----------------------------------------------------------------------------
4185 // wxWinModule
4186 // ----------------------------------------------------------------------------
4187 
4188 class wxWinModule : public wxModule
4189 {
4190 public:
4191     bool OnInit();
4192     void OnExit();
4193 
4194 private:
4195     wxDECLARE_DYNAMIC_CLASS(wxWinModule);
4196 };
4197 
4198 wxIMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule);
4199 
OnInit()4200 bool wxWinModule::OnInit()
4201 {
4202     // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4203     // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4204 
4205     return true;
4206 }
4207 
OnExit()4208 void wxWinModule::OnExit()
4209 {
4210     if (g_eraseGC)
4211         gdk_gc_unref( g_eraseGC );
4212 }
4213 
GTKGetDrawingWindow() const4214 GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
4215 {
4216     GdkWindow* window = NULL;
4217     if (m_wxwindow)
4218         window = GTK_PIZZA(m_wxwindow)->bin_window;
4219     return window;
4220 }
4221