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