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