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