1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/minifram.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/minifram.h"
18 #include "wx/settings.h"
19 #include "wx/dcclient.h"
23 #include "wx/gtk/dcclient.h"
27 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
31 extern bool g_blockEventsOnDrag
;
32 extern bool g_blockEventsOnScroll
;
34 //-----------------------------------------------------------------------------
35 // "expose_event" of m_mainWidget
36 //-----------------------------------------------------------------------------
38 // StepColour() it a utility function that simply darkens
39 // or lightens a color, based on the specified percentage
40 static wxColor
StepColour(const wxColor
& c
, int percent
)
42 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
43 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
44 (unsigned char)wxMin((g
*percent
)/100,255),
45 (unsigned char)wxMin((b
*percent
)/100,255));
48 static wxColor
LightContrastColour(const wxColour
& c
)
52 // if the color is especially dark, then
53 // make the contrast even lighter
54 if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128)
57 return StepColour(c
, amount
);
61 static gboolean
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
)
63 if (!win
->m_hasVMT
|| gdk_event
->count
> 0 ||
64 gdk_event
->window
!= widget
->window
)
69 gtk_paint_shadow (widget
->style
,
73 NULL
, NULL
, NULL
, // FIXME: No clipping?
75 win
->m_width
, win
->m_height
);
77 int style
= win
->GetWindowStyle();
81 wxDCImpl
*impl
= dc
.GetImpl();
82 wxClientDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxClientDCImpl
);
83 gtk_impl
->m_gdkwindow
= widget
->window
; // Hack alert
85 if (style
& wxRESIZE_BORDER
)
87 dc
.SetBrush( *wxGREY_BRUSH
);
88 dc
.SetPen( *wxTRANSPARENT_PEN
);
89 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
92 if (win
->m_miniTitle
&& !win
->GetTitle().empty())
94 dc
.SetFont( *wxSMALL_FONT
);
96 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
98 dc
.SetPen( *wxTRANSPARENT_PEN
);
99 dc
.DrawRectangle( win
->m_miniEdge
-1,
101 win
->m_width
- (2*(win
->m_miniEdge
-1)),
104 dc
.SetTextForeground( *wxWHITE
);
105 dc
.DrawText( win
->GetTitle(), 6, 4 );
107 if (style
& wxCLOSE_BOX
)
108 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true );
115 //-----------------------------------------------------------------------------
116 // "button_press_event" of m_mainWidget
117 //-----------------------------------------------------------------------------
121 gtk_window_button_press_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
123 if (!win
->m_hasVMT
|| gdk_event
->window
!= widget
->window
)
125 if (g_blockEventsOnDrag
) return TRUE
;
126 if (g_blockEventsOnScroll
) return TRUE
;
128 if (win
->m_isDragging
) return TRUE
;
130 int style
= win
->GetWindowStyle();
132 int y
= (int)gdk_event
->y
;
133 int x
= (int)gdk_event
->x
;
135 if ((style
& wxRESIZE_BORDER
) &&
136 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
138 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
140 GdkWindow
*source
= widget
->window
;
144 gdk_window_get_origin( source
, &org_x
, &org_y
);
146 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
147 GDK_WINDOW_EDGE_SOUTH_EAST
,
156 if (win
->m_miniTitle
&& (style
& wxCLOSE_BOX
))
158 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
165 if (y
>= win
->m_miniEdge
+ win
->m_miniTitle
)
168 gdk_window_raise( win
->m_widget
->window
);
170 gdk_pointer_grab( widget
->window
, FALSE
,
172 (GDK_BUTTON_PRESS_MASK
|
173 GDK_BUTTON_RELEASE_MASK
|
174 GDK_POINTER_MOTION_MASK
|
175 GDK_POINTER_MOTION_HINT_MASK
|
176 GDK_BUTTON_MOTION_MASK
|
177 GDK_BUTTON1_MOTION_MASK
),
180 (unsigned int) GDK_CURRENT_TIME
);
187 win
->m_isDragging
= true;
193 //-----------------------------------------------------------------------------
194 // "button_release_event" of m_mainWidget
195 //-----------------------------------------------------------------------------
199 gtk_window_button_release_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
201 if (!win
->m_hasVMT
|| gdk_event
->window
!= widget
->window
)
203 if (g_blockEventsOnDrag
) return TRUE
;
204 if (g_blockEventsOnScroll
) return TRUE
;
205 if (!win
->m_isDragging
) return TRUE
;
207 win
->m_isDragging
= false;
209 int x
= (int)gdk_event
->x
;
210 int y
= (int)gdk_event
->y
;
212 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
215 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
216 x
+= org_x
- win
->m_diffX
;
217 y
+= org_y
- win
->m_diffY
;
220 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
226 //-----------------------------------------------------------------------------
227 // "leave_notify_event" of m_mainWidget
228 //-----------------------------------------------------------------------------
232 gtk_window_leave_callback(GtkWidget
*widget
,
233 GdkEventCrossing
* gdk_event
,
236 if (!win
->m_hasVMT
) return FALSE
;
237 if (g_blockEventsOnDrag
) return FALSE
;
238 if (gdk_event
->window
!= widget
->window
)
241 gdk_window_set_cursor( widget
->window
, NULL
);
247 //-----------------------------------------------------------------------------
248 // "motion_notify_event" of m_mainWidget
249 //-----------------------------------------------------------------------------
253 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
255 if (!win
->m_hasVMT
|| gdk_event
->window
!= widget
->window
)
257 if (g_blockEventsOnDrag
) return TRUE
;
258 if (g_blockEventsOnScroll
) return TRUE
;
260 if (gdk_event
->is_hint
)
264 GdkModifierType state
;
265 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
268 gdk_event
->state
= state
;
271 int style
= win
->GetWindowStyle();
273 int x
= (int)gdk_event
->x
;
274 int y
= (int)gdk_event
->y
;
276 if (!win
->m_isDragging
)
278 if (style
& wxRESIZE_BORDER
)
280 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
281 gdk_window_set_cursor( widget
->window
, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER
) );
283 gdk_window_set_cursor( widget
->window
, NULL
);
284 win
->GTKUpdateCursor(false);
289 win
->m_oldX
= x
- win
->m_diffX
;
290 win
->m_oldY
= y
- win
->m_diffY
;
294 gdk_window_get_origin( widget
->window
, &org_x
, &org_y
);
295 x
+= org_x
- win
->m_diffX
;
296 y
+= org_y
- win
->m_diffY
;
299 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
305 //-----------------------------------------------------------------------------
307 //-----------------------------------------------------------------------------
309 static unsigned char close_bits
[]={
310 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
311 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
312 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
315 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
317 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
318 const wxPoint
&pos
, const wxSize
&size
,
319 long style
, const wxString
&name
)
322 if (style
& wxCAPTION
)
325 if (style
& wxRESIZE_BORDER
)
329 m_isDragging
= false;
335 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
337 // Use a GtkEventBox for the title and borders. Using m_widget for this
338 // almost works, except that setting the resize cursor has no effect.
339 GtkWidget
* eventbox
= gtk_event_box_new();
340 gtk_widget_add_events(eventbox
,
341 GDK_POINTER_MOTION_MASK
|
342 GDK_POINTER_MOTION_HINT_MASK
);
343 gtk_widget_show(eventbox
);
344 // Use a GtkAlignment to position m_mainWidget inside the decorations
345 GtkWidget
* alignment
= gtk_alignment_new(0, 0, 1, 1);
346 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment
),
347 m_miniTitle
+ m_miniEdge
, m_miniEdge
, m_miniEdge
, m_miniEdge
);
348 gtk_widget_show(alignment
);
349 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
350 gtk_widget_reparent(m_mainWidget
, alignment
);
351 gtk_container_add(GTK_CONTAINER(eventbox
), alignment
);
352 gtk_container_add(GTK_CONTAINER(m_widget
), eventbox
);
356 if (style
& wxRESIZE_BORDER
)
357 m_gdkFunc
= GDK_FUNC_RESIZE
;
358 gtk_window_set_default_size(GTK_WINDOW(m_widget
), m_width
, m_height
);
359 m_decorSize
.Set(0, 0);
362 // don't allow sizing smaller than decorations
364 geom
.min_width
= 2 * m_miniEdge
;
365 geom
.min_height
= 2 * m_miniEdge
+ m_miniTitle
;
366 gtk_window_set_geometry_hints(GTK_WINDOW(m_widget
), NULL
, &geom
, GDK_HINT_MIN_SIZE
);
368 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
370 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
373 if (m_miniTitle
&& (style
& wxCLOSE_BOX
))
375 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
376 img
.Replace(0,0,0,123,123,123);
377 img
.SetMaskColour(123,123,123);
378 m_closeButton
= wxBitmap( img
);
381 /* these are called when the borders are drawn */
382 g_signal_connect_after(eventbox
, "expose_event",
383 G_CALLBACK (gtk_window_own_expose_callback
), this );
385 /* these are required for dragging the mini frame around */
386 g_signal_connect (eventbox
, "button_press_event",
387 G_CALLBACK (gtk_window_button_press_callback
), this);
388 g_signal_connect (eventbox
, "button_release_event",
389 G_CALLBACK (gtk_window_button_release_callback
), this);
390 g_signal_connect (eventbox
, "motion_notify_event",
391 G_CALLBACK (gtk_window_motion_notify_callback
), this);
392 g_signal_connect (eventbox
, "leave_notify_event",
393 G_CALLBACK (gtk_window_leave_callback
), this);
397 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const
399 wxFrame::DoGetClientSize(width
, height
);
402 *width
-= 2 * m_miniEdge
;
403 if (*width
< 0) *width
= 0;
407 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
408 if (*height
< 0) *height
= 0;
412 // Keep min size at least as large as decorations
413 void wxMiniFrame::DoSetSizeHints(int minW
, int minH
, int maxW
, int maxH
, int incW
, int incH
)
415 const int w
= 2 * m_miniEdge
;
416 const int h
= 2 * m_miniEdge
+ m_miniTitle
;
417 if (minW
< w
) minW
= w
;
418 if (minH
< h
) minH
= h
;
419 wxFrame::DoSetSizeHints(minW
, minH
, maxW
, maxH
, incW
, incH
);
422 void wxMiniFrame::SetTitle( const wxString
&title
)
424 wxFrame::SetTitle( title
);
426 GtkWidget
* widget
= GTK_BIN(m_widget
)->child
;
428 gdk_window_invalidate_rect(widget
->window
, NULL
, false);
431 #endif // wxUSE_MINIFRAME