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