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