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