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