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" 
  16 #include "wx/gtk/dcclient.h" 
  19     #include "wx/settings.h" 
  20     #include "wx/dcclient.h" 
  26 //----------------------------------------------------------------------------- 
  28 //----------------------------------------------------------------------------- 
  30 extern bool        g_blockEventsOnDrag
; 
  31 extern bool        g_blockEventsOnScroll
; 
  33 //----------------------------------------------------------------------------- 
  34 // "expose_event" of m_mainWidget 
  35 //----------------------------------------------------------------------------- 
  37 // StepColour() it a utility function that simply darkens 
  38 // or lightens a color, based on the specified percentage 
  39 static wxColor 
StepColour(const wxColor
& c
, int percent
) 
  41     int r 
= c
.Red(), g 
= c
.Green(), b 
= c
.Blue(); 
  42     return wxColour((unsigned char)wxMin((r
*percent
)/100,255), 
  43                     (unsigned char)wxMin((g
*percent
)/100,255), 
  44                     (unsigned char)wxMin((b
*percent
)/100,255)); 
  47 static wxColor 
LightContrastColour(const wxColour
& c
) 
  51     // if the color is especially dark, then 
  52     // make the contrast even lighter 
  53     if (c
.Red() < 128 && c
.Green() < 128 && c
.Blue() < 128) 
  56     return StepColour(c
, amount
); 
  60 static gboolean 
gtk_window_own_expose_callback(GtkWidget
* widget
, GdkEventExpose
* gdk_event
, wxMiniFrame
* win
) 
  62     if (!win
->m_hasVMT 
|| gdk_event
->count 
> 0) 
  65     gtk_paint_shadow (widget
->style
, 
  69                       NULL
, NULL
, NULL
, // FIXME: No clipping? 
  71                       win
->m_width
, win
->m_height
); 
  73     int style 
= win
->GetWindowStyle(); 
  77     wxDCImpl 
*impl 
= dc
.GetImpl(); 
  78     wxClientDCImpl 
*gtk_impl 
= wxDynamicCast( impl
, wxClientDCImpl 
); 
  79     gtk_impl
->m_gdkwindow 
= widget
->window
; // Hack alert 
  81     if (style 
& wxRESIZE_BORDER
) 
  83         dc
.SetBrush( *wxGREY_BRUSH 
); 
  84         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
  85         dc
.DrawRectangle( win
->m_width 
- 14, win
->m_height
-14, 14, 14 ); 
  88     if (!win
->GetTitle().empty() && 
  89         ((style 
& wxCAPTION
) || 
  90          (style 
& wxTINY_CAPTION_HORIZ
) || 
  91          (style 
& wxTINY_CAPTION_VERT
))) 
  93         dc
.SetFont( *wxSMALL_FONT 
); 
  95         wxBrush 
brush( LightContrastColour( wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
) ) ); 
  97         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
  98         dc
.DrawRectangle( win
->m_miniEdge
-1,  
 100                           win
->m_width 
- (2*(win
->m_miniEdge
-1)), 
 103         dc
.SetTextForeground( *wxWHITE 
); 
 104         dc
.DrawText( win
->GetTitle(), 6, 4 ); 
 106         if (style 
& wxCLOSE_BOX
) 
 107             dc
.DrawBitmap( win
->m_closeButton
, win
->m_width
-18, 3, true ); 
 114 //----------------------------------------------------------------------------- 
 115 // "button_press_event" of m_mainWidget 
 116 //----------------------------------------------------------------------------- 
 119 static gint 
gtk_window_button_press_callback( GtkWidget 
*widget
, GdkEventButton 
*gdk_event
, wxMiniFrame 
*win 
) 
 121     if (!win
->m_hasVMT
) return FALSE
; 
 122     if (g_blockEventsOnDrag
) return TRUE
; 
 123     if (g_blockEventsOnScroll
) return TRUE
; 
 125     if (win
->m_isDragging
) return TRUE
; 
 127     int style 
= win
->GetWindowStyle(); 
 129     int y 
= (int)gdk_event
->y
; 
 130     int x 
= (int)gdk_event
->x
; 
 132     if ((style 
& wxRESIZE_BORDER
) && 
 133         (x 
> win
->m_width
-14) && (y 
> win
->m_height
-14)) 
 135         GtkWidget 
*ancestor 
= gtk_widget_get_toplevel( widget 
); 
 137         GdkWindow 
*source 
= widget
->window
; 
 141         gdk_window_get_origin( source
, &org_x
, &org_y 
); 
 143         gtk_window_begin_resize_drag (GTK_WINDOW (ancestor
), 
 144                                   GDK_WINDOW_EDGE_SOUTH_EAST
, 
 153     if ((style 
& wxCLOSE_BOX
) && 
 154         ((style 
& wxCAPTION
) || (style 
& wxTINY_CAPTION_HORIZ
) || (style 
& wxTINY_CAPTION_VERT
))) 
 156         if ((y 
> 3) && (y 
< 19) && (x 
> win
->m_width
-19) && (x 
< win
->m_width
-3)) 
 163     if (y 
> win
->m_miniEdge
-1 + 15) return TRUE
; 
 165     gdk_window_raise( win
->m_widget
->window 
); 
 167     gdk_pointer_grab( widget
->window
, FALSE
, 
 169                          (GDK_BUTTON_PRESS_MASK 
| 
 170                           GDK_BUTTON_RELEASE_MASK 
| 
 171                           GDK_POINTER_MOTION_MASK        
| 
 172                           GDK_POINTER_MOTION_HINT_MASK  
| 
 173                           GDK_BUTTON_MOTION_MASK        
| 
 174                           GDK_BUTTON1_MOTION_MASK
), 
 177                       (unsigned int) GDK_CURRENT_TIME 
); 
 184     win
->m_isDragging 
= true; 
 190 //----------------------------------------------------------------------------- 
 191 // "button_release_event" of m_mainWidget 
 192 //----------------------------------------------------------------------------- 
 195 static gint 
gtk_window_button_release_callback( GtkWidget 
*widget
, GdkEventButton 
*gdk_event
, wxMiniFrame 
*win 
) 
 197     if (!win
->m_hasVMT
) return FALSE
; 
 198     if (g_blockEventsOnDrag
) return TRUE
; 
 199     if (g_blockEventsOnScroll
) return TRUE
; 
 201     if (!win
->m_isDragging
) return TRUE
; 
 203     win
->m_isDragging 
= false; 
 205     int x 
= (int)gdk_event
->x
; 
 206     int y 
= (int)gdk_event
->y
; 
 208     gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME 
); 
 211     gdk_window_get_origin( widget
->window
, &org_x
, &org_y 
); 
 212     x 
+= org_x 
- win
->m_diffX
; 
 213     y 
+= org_y 
- win
->m_diffY
; 
 216     gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y 
); 
 222 //----------------------------------------------------------------------------- 
 223 // "leave_notify_event" of m_mainWidget 
 224 //----------------------------------------------------------------------------- 
 228 gtk_window_leave_callback(GtkWidget 
*widget
, 
 229                           GdkEventCrossing 
* WXUNUSED(gdk_event
), 
 232     if (!win
->m_hasVMT
) return FALSE
; 
 233     if (g_blockEventsOnDrag
) return FALSE
; 
 235     gdk_window_set_cursor( widget
->window
, NULL 
); 
 241 //----------------------------------------------------------------------------- 
 242 // "motion_notify_event" of m_mainWidget 
 243 //----------------------------------------------------------------------------- 
 247 gtk_window_motion_notify_callback( GtkWidget 
*widget
, GdkEventMotion 
*gdk_event
, wxMiniFrame 
*win 
) 
 249     if (!win
->m_hasVMT
) return FALSE
; 
 250     if (g_blockEventsOnDrag
) return TRUE
; 
 251     if (g_blockEventsOnScroll
) return TRUE
; 
 253     if (gdk_event
->is_hint
) 
 257        GdkModifierType state
; 
 258        gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
); 
 261        gdk_event
->state 
= state
; 
 264     int style 
= win
->GetWindowStyle(); 
 266     int x 
= (int)gdk_event
->x
; 
 267     int y 
= (int)gdk_event
->y
; 
 269     if (!win
->m_isDragging
) 
 271         if (style 
& wxRESIZE_BORDER
) 
 273             if ((x 
> win
->m_width
-14) && (y 
> win
->m_height
-14)) 
 274                gdk_window_set_cursor( widget
->window
, gdk_cursor_new( GDK_BOTTOM_RIGHT_CORNER 
) ); 
 276                gdk_window_set_cursor( widget
->window
, NULL 
); 
 281     win
->m_oldX 
= x 
- win
->m_diffX
; 
 282     win
->m_oldY 
= y 
- win
->m_diffY
; 
 286     gdk_window_get_origin( widget
->window
, &org_x
, &org_y 
); 
 287     x 
+= org_x 
- win
->m_diffX
; 
 288     y 
+= org_y 
- win
->m_diffY
; 
 291     gtk_window_move( GTK_WINDOW(win
->m_widget
), x
, y 
); 
 297 //----------------------------------------------------------------------------- 
 299 //----------------------------------------------------------------------------- 
 301 static unsigned char close_bits
[]={ 
 302     0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8, 
 303     0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef, 
 304     0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 
 307 IMPLEMENT_DYNAMIC_CLASS(wxMiniFrame
,wxFrame
) 
 309 bool wxMiniFrame::Create( wxWindow 
*parent
, wxWindowID id
, const wxString 
&title
, 
 310       const wxPoint 
&pos
, const wxSize 
&size
, 
 311       long style
, const wxString 
&name 
) 
 313     if ((style 
& wxCAPTION
) || (style 
& wxTINY_CAPTION_HORIZ
) || (style 
& wxTINY_CAPTION_VERT
)) 
 316     if (style 
& wxRESIZE_BORDER
) 
 320     m_isDragging 
= false; 
 326     wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name 
); 
 328     // Use a GtkEventBox for the title and borders. Using m_widget for this 
 329     // almost works, except that setting the resize cursor has no effect. 
 330     GtkWidget
* eventbox 
= gtk_event_box_new(); 
 331     gtk_widget_add_events(eventbox
, 
 332         GDK_POINTER_MOTION_MASK 
| 
 333         GDK_POINTER_MOTION_HINT_MASK
); 
 334     gtk_widget_show(eventbox
); 
 335     // Use a GtkAlignment to position m_mainWidget inside the decorations 
 336     GtkWidget
* alignment 
= gtk_alignment_new(0, 0, 1, 1); 
 337     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment
), 
 338         m_miniTitle 
+ m_miniEdge
, m_miniEdge
, m_miniEdge
, m_miniEdge
); 
 339     gtk_widget_show(alignment
); 
 340     // The GtkEventBox and GtkAlignment go between m_widget and m_mainWidget 
 341     gtk_widget_reparent(m_mainWidget
, alignment
); 
 342     gtk_container_add(GTK_CONTAINER(eventbox
), alignment
); 
 343     gtk_container_add(GTK_CONTAINER(m_widget
), eventbox
); 
 347     if (style 
& wxRESIZE_BORDER
) 
 348        m_gdkFunc 
= GDK_FUNC_RESIZE
; 
 350     // don't allow sizing smaller than decorations 
 352     geom
.min_width  
= 2 * m_miniEdge
; 
 353     geom
.min_height 
= 2 * m_miniEdge 
+ m_miniTitle
; 
 354     gtk_window_set_geometry_hints(GTK_WINDOW(m_widget
), NULL
, &geom
, GDK_HINT_MIN_SIZE
); 
 356     if (m_parent 
&& (GTK_IS_WINDOW(m_parent
->m_widget
))) 
 358         gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) ); 
 361     if ((style 
& wxCLOSE_BOX
) && 
 362         ((style 
& wxCAPTION
) || (style 
& wxTINY_CAPTION_HORIZ
) || (style 
& wxTINY_CAPTION_VERT
))) 
 364         wxImage img 
= wxBitmap((const char*)close_bits
, 16, 16).ConvertToImage(); 
 365         img
.Replace(0,0,0,123,123,123); 
 366         img
.SetMaskColour(123,123,123); 
 367         m_closeButton 
= wxBitmap( img 
); 
 370     /* these are called when the borders are drawn */ 
 371     g_signal_connect_after(eventbox
, "expose_event", 
 372                       G_CALLBACK (gtk_window_own_expose_callback
), this ); 
 374     /* these are required for dragging the mini frame around */ 
 375     g_signal_connect (eventbox
, "button_press_event", 
 376                       G_CALLBACK (gtk_window_button_press_callback
), this); 
 377     g_signal_connect (eventbox
, "button_release_event", 
 378                       G_CALLBACK (gtk_window_button_release_callback
), this); 
 379     g_signal_connect (eventbox
, "motion_notify_event", 
 380                       G_CALLBACK (gtk_window_motion_notify_callback
), this); 
 381     g_signal_connect (eventbox
, "leave_notify_event", 
 382                       G_CALLBACK (gtk_window_leave_callback
), this); 
 386 void wxMiniFrame::DoGetClientSize(int* width
, int* height
) const 
 388     wxFrame::DoGetClientSize(width
, height
); 
 391         *width 
-= 2 * m_miniEdge
; 
 392         if (*width 
< 0) *width 
= 0; 
 396         *height 
-= m_miniTitle 
+ 2 * m_miniEdge
; 
 397         if (*height 
< 0) *height 
= 0; 
 401 // Keep min size at least as large as decorations 
 402 void wxMiniFrame::DoSetSizeHints(int minW
, int minH
, int maxW
, int maxH
, int incW
, int incH
) 
 404     const int w 
= 2 * m_miniEdge
; 
 405     const int h 
= 2 * m_miniEdge 
+ m_miniTitle
; 
 406     if (minW 
< w
) minW 
= w
; 
 407     if (minH 
< h
) minH 
= h
; 
 408     wxFrame::DoSetSizeHints(minW
, minH
, maxW
, maxH
, incW
, incH
); 
 411 void wxMiniFrame::SetTitle( const wxString 
&title 
) 
 413     wxFrame::SetTitle( title 
); 
 415     GtkWidget
* widget 
= GTK_BIN(m_widget
)->child
; 
 417         gdk_window_invalidate_rect(widget
->window
, NULL
, false); 
 420 #endif // wxUSE_MINIFRAME