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