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