~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/gtk1/window.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

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