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