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