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