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"
26 #include "wx/gtk/private/gtk2-compat.h"
28 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
32 extern bool g_blockEventsOnDrag
;
33 extern bool g_blockEventsOnScroll
;
35 //-----------------------------------------------------------------------------
36 // "expose_event" of m_mainWidget
37 //-----------------------------------------------------------------------------
39 // StepColour() it a utility function that simply darkens
40 // or lightens a color, based on the specified percentage
41 static wxColor
StepColour(const wxColor
& c
, int percent
)
43 int r
= c
.Red(), g
= c
.Green(), b
= c
.Blue();
44 return wxColour((unsigned char)wxMin((r
*percent
)/100,255),
45 (unsigned char)wxMin((g
*percent
)/100,255),
46 (unsigned char)wxMin((b
*percent
)/100,255));
49 static wxColor
LightContrastColour(const wxColour
& c
)
53 // if the color is especially dark, then
54 // make the contrast even lighter
55 if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128)
58 return StepColour(c
, amount
);
62 static gboolean
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
)
64 if (!win
->m_hasVMT
|| gdk_event
->count
> 0 ||
65 gdk_event
->window
!= gtk_widget_get_window(widget
))
70 gtk_paint_shadow (gtk_widget_get_style(widget
),
71 gtk_widget_get_window(widget
),
74 NULL
, NULL
, NULL
, // FIXME: No clipping?
76 win
->m_width
, win
->m_height
);
78 int style
= win
->GetWindowStyle();
82 wxDCImpl
*impl
= dc
.GetImpl();
83 wxClientDCImpl
*gtk_impl
= wxDynamicCast( impl
, wxClientDCImpl
);
84 gtk_impl
->m_gdkwindow
= gtk_widget_get_window(widget
); // Hack alert
86 if (style
& wxRESIZE_BORDER
)
88 dc
.SetBrush( *wxGREY_BRUSH
);
89 dc
.SetPen( *wxTRANSPARENT_PEN
);
90 dc
.DrawRectangle( win
->m_width
- 14, win
->m_height
-14, 14, 14 );
93 if (win
->m_miniTitle
&& !win
->GetTitle().empty())
95 dc
.SetFont( *wxSMALL_FONT
);
97 wxBrush
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) );
99 dc
.SetPen( *wxTRANSPARENT_PEN
);
100 dc
.DrawRectangle( win
->m_miniEdge
-1,
102 win
->m_width
- (2*(win
->m_miniEdge
-1)),
105 dc
.SetTextForeground( *wxWHITE
);
106 dc
.DrawText( win
->GetTitle(), 6, 4 );
108 if (style
& wxCLOSE_BOX
)
109 dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true );
116 //-----------------------------------------------------------------------------
117 // "button_press_event" of m_mainWidget
118 //-----------------------------------------------------------------------------
122 gtk_window_button_press_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
124 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
126 if (g_blockEventsOnDrag
) return TRUE
;
127 if (g_blockEventsOnScroll
) return TRUE
;
129 if (win
->m_isDragging
) return TRUE
;
131 int style
= win
->GetWindowStyle();
133 int y
= (int)gdk_event
->y
;
134 int x
= (int)gdk_event
->x
;
136 if ((style
& wxRESIZE_BORDER
) &&
137 (x
> win
->m_width
-14) && (y
> win
->m_height
-14))
139 GtkWidget
*ancestor
= gtk_widget_get_toplevel( widget
);
141 GdkWindow
*source
= gtk_widget_get_window(widget
);
145 gdk_window_get_origin( source
, &org_x
, &org_y
);
147 gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
),
148 GDK_WINDOW_EDGE_SOUTH_EAST
,
157 if (win
->m_miniTitle
&& (style
& wxCLOSE_BOX
))
159 if ((y
> 3) && (y
< 19) && (x
> win
->m_width
-19) && (x
< win
->m_width
-3))
166 if (y
>= win
->m_miniEdge
+ win
->m_miniTitle
)
169 gdk_window_raise(gtk_widget_get_window(win
->m_widget
));
171 gdk_pointer_grab( gtk_widget_get_window(widget
), false,
173 (GDK_BUTTON_PRESS_MASK
|
174 GDK_BUTTON_RELEASE_MASK
|
175 GDK_POINTER_MOTION_MASK
|
176 GDK_POINTER_MOTION_HINT_MASK
|
177 GDK_BUTTON_MOTION_MASK
|
178 GDK_BUTTON1_MOTION_MASK
),
181 (unsigned int) GDK_CURRENT_TIME
);
188 win
->m_isDragging
= true;
194 //-----------------------------------------------------------------------------
195 // "button_release_event" of m_mainWidget
196 //-----------------------------------------------------------------------------
200 gtk_window_button_release_callback(GtkWidget
* widget
, GdkEventButton
* gdk_event
, wxMiniFrame
* win
)
202 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
204 if (g_blockEventsOnDrag
) return TRUE
;
205 if (g_blockEventsOnScroll
) return TRUE
;
206 if (!win
->m_isDragging
) return TRUE
;
208 win
->m_isDragging
= false;
210 int x
= (int)gdk_event
->x
;
211 int y
= (int)gdk_event
->y
;
213 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
216 gdk_window_get_origin(gtk_widget_get_window(widget
), &org_x
, &org_y
);
217 x
+= org_x
- win
->m_diffX
;
218 y
+= org_y
- win
->m_diffY
;
221 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
227 //-----------------------------------------------------------------------------
228 // "leave_notify_event" of m_mainWidget
229 //-----------------------------------------------------------------------------
233 gtk_window_leave_callback(GtkWidget
*widget
,
234 GdkEventCrossing
* gdk_event
,
237 if (!win
->m_hasVMT
) return FALSE
;
238 if (g_blockEventsOnDrag
) return FALSE
;
239 if (gdk_event
->window
!= gtk_widget_get_window(widget
))
242 gdk_window_set_cursor(gtk_widget_get_window(widget
), NULL
);
248 //-----------------------------------------------------------------------------
249 // "motion_notify_event" of m_mainWidget
250 //-----------------------------------------------------------------------------
254 gtk_window_motion_notify_callback( GtkWidget
*widget
, GdkEventMotion
*gdk_event
, wxMiniFrame
*win
)
256 if (!win
->m_hasVMT
|| gdk_event
->window
!= gtk_widget_get_window(widget
))
258 if (g_blockEventsOnDrag
) return TRUE
;
259 if (g_blockEventsOnScroll
) return TRUE
;
261 if (gdk_event
->is_hint
)
265 GdkModifierType state
;
266 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
269 gdk_event
->state
= state
;
272 int style
= win
->GetWindowStyle();
274 int x
= (int)gdk_event
->x
;
275 int y
= (int)gdk_event
->y
;
277 if (!win
->m_isDragging
)
279 if (style
& wxRESIZE_BORDER
)
281 if ((x
> win
->m_width
-14) && (y
> win
->m_height
-14))
282 gdk_window_set_cursor(gtk_widget_get_window(widget
), gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER
));
284 gdk_window_set_cursor(gtk_widget_get_window(widget
), NULL
);
285 win
->GTKUpdateCursor(false);
290 win
->m_oldX
= x
- win
->m_diffX
;
291 win
->m_oldY
= y
- win
->m_diffY
;
295 gdk_window_get_origin(gtk_widget_get_window(widget
), &org_x
, &org_y
);
296 x
+= org_x
- win
->m_diffX
;
297 y
+= org_y
- win
->m_diffY
;
300 gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y
);
306 //-----------------------------------------------------------------------------
308 //-----------------------------------------------------------------------------
310 static unsigned char close_bits
[]={
311 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
312 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
313 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
316 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
)
318 bool wxMiniFrame::Create( wxWindow
*parent
, wxWindowID id
, const wxString
&title
,
319 const wxPoint
&pos
, const wxSize
&size
,
320 long style
, const wxString
&name
)
323 if (style
& wxCAPTION
)
326 if (style
& wxRESIZE_BORDER
)
330 m_isDragging
= false;
336 // don't allow sizing smaller than decorations
337 int minWidth
= 2 * m_miniEdge
;
338 int minHeight
= 2 * m_miniEdge
+ m_miniTitle
;
339 if (m_minWidth
< minWidth
)
340 m_minWidth
= minWidth
;
341 if (m_minHeight
< minHeight
)
342 m_minHeight
= minHeight
;
344 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
346 // Use a GtkEventBox for the title and borders. Using m_widget for this
347 // almost works, except that setting the resize cursor has no effect.
348 GtkWidget
* eventbox
= gtk_event_box_new();
349 gtk_widget_add_events(eventbox
,
350 GDK_POINTER_MOTION_MASK
|
351 GDK_POINTER_MOTION_HINT_MASK
);
352 gtk_widget_show(eventbox
);
353 // Use a GtkAlignment to position m_mainWidget inside the decorations
354 GtkWidget
* alignment
= gtk_alignment_new(0, 0, 1, 1);
355 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment
),
356 m_miniTitle
+ m_miniEdge
, m_miniEdge
, m_miniEdge
, m_miniEdge
);
357 gtk_widget_show(alignment
);
358 // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget
359 gtk_widget_reparent(m_mainWidget
, alignment
);
360 gtk_container_add(GTK_CONTAINER(eventbox
), alignment
);
361 gtk_container_add(GTK_CONTAINER(m_widget
), eventbox
);
365 if (style
& wxRESIZE_BORDER
)
366 m_gdkFunc
= GDK_FUNC_RESIZE
;
367 gtk_window_set_default_size(GTK_WINDOW(m_widget
), m_width
, m_height
);
368 m_decorSize
.Set(0, 0);
371 if (m_parent
&& (GTK_IS_WINDOW(m_parent
->m_widget
)))
373 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
376 if (m_miniTitle
&& (style
& wxCLOSE_BOX
))
378 wxImage img
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage();
379 img
.Replace(0,0,0,123,123,123);
380 img
.SetMaskColour(123,123,123);
381 m_closeButton
= wxBitmap( img
);
384 /* these are called when the borders are drawn */
385 g_signal_connect_after(eventbox
, "expose_event",
386 G_CALLBACK (gtk_window_own_expose_callback
), this );
388 /* these are required for dragging the mini frame around */
389 g_signal_connect (eventbox
, "button_press_event",
390 G_CALLBACK (gtk_window_button_press_callback
), this);
391 g_signal_connect (eventbox
, "button_release_event",
392 G_CALLBACK (gtk_window_button_release_callback
), this);
393 g_signal_connect (eventbox
, "motion_notify_event",
394 G_CALLBACK (gtk_window_motion_notify_callback
), this);
395 g_signal_connect (eventbox
, "leave_notify_event",
396 G_CALLBACK (gtk_window_leave_callback
), this);
400 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const
402 wxFrame::DoGetClientSize(width
, height
);
405 *width
-= 2 * m_miniEdge
;
406 if (*width
< 0) *width
= 0;
410 *height
-= m_miniTitle
+ 2 * m_miniEdge
;
411 if (*height
< 0) *height
= 0;
415 // Keep min size at least as large as decorations
416 void wxMiniFrame::DoSetSizeHints(int minW
, int minH
, int maxW
, int maxH
, int incW
, int incH
)
418 const int w
= 2 * m_miniEdge
;
419 const int h
= 2 * m_miniEdge
+ m_miniTitle
;
420 if (minW
< w
) minW
= w
;
421 if (minH
< h
) minH
= h
;
422 wxFrame::DoSetSizeHints(minW
, minH
, maxW
, maxH
, incW
, incH
);
425 void wxMiniFrame::SetTitle( const wxString
&title
)
427 wxFrame::SetTitle( title
);
429 GdkWindow
* window
= gtk_widget_get_window(gtk_bin_get_child(GTK_BIN(m_widget
)));
431 gdk_window_invalidate_rect(window
, NULL
, false);
434 #endif // wxUSE_MINIFRAME