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