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