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