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