// Draw the caption buttons in their current state. Returns the // number of pixels on the right of the caption that are occupied // by the buttons. private static int DrawCaptionButtons (Graphics graphics, Rectangle rect, CaptionFlags flags, CaptionFlags buttonsToDraw) { int subtract = 2; if((flags & CaptionFlags.HasClose) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.ClosePressed) != 0), ((buttonsToDraw & CaptionFlags.HasClose) != 0), graphics.dpy.bitmaps.Close); if((flags & (CaptionFlags.HasMaximize | CaptionFlags.HasRestore | CaptionFlags.HasMinimize)) != 0) { // Leave a gap between the close button and the others. subtract += 2; } } if((flags & CaptionFlags.HasMaximize) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.MaximizePressed) != 0), ((buttonsToDraw & CaptionFlags.HasMaximize) != 0), graphics.dpy.bitmaps.Maximize); } if((flags & CaptionFlags.HasRestore) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.RestorePressed) != 0), ((buttonsToDraw & CaptionFlags.HasRestore) != 0), graphics.dpy.bitmaps.Restore); } if((flags & CaptionFlags.HasMinimize) != 0) { subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.MinimizePressed) != 0), ((buttonsToDraw & CaptionFlags.HasMinimize) != 0), graphics.dpy.bitmaps.Minimize); } if((flags & CaptionFlags.HasHelp) != 0) { // Leave a gap between the help button and the others. subtract += 2; subtract += DrawCaptionButton (graphics, rect, subtract, ((flags & CaptionFlags.HelpPressed) != 0), ((buttonsToDraw & CaptionFlags.HasHelp) != 0), graphics.dpy.bitmaps.Help); } if(subtract > 2) { // Leave a gap between the buttons and the text. return subtract + 2; } else { // There are no buttons, so no need for an extra gap. return 2; } }
// Change the state of a caption button. Returns true if the // button was pressed before we changed its state. private bool ChangeButtonState(HitTest hitTest, bool pressed) { // Determine what change we need to apply. CaptionFlags buttonsToDraw = (CaptionFlags)0; CaptionFlags pressedState = (CaptionFlags)0; CaptionFlags origFlags = flags; switch(hitTest) { case HitTest.Close: { buttonsToDraw = CaptionFlags.HasClose; pressedState = CaptionFlags.ClosePressed; } break; case HitTest.Maximize: { buttonsToDraw = CaptionFlags.HasMaximize; pressedState = CaptionFlags.MaximizePressed; } break; case HitTest.Minimize: { buttonsToDraw = CaptionFlags.HasMinimize; pressedState = CaptionFlags.MinimizePressed; } break; case HitTest.Restore: { buttonsToDraw = CaptionFlags.HasRestore; pressedState = CaptionFlags.RestorePressed; } break; case HitTest.Help: { buttonsToDraw = CaptionFlags.HasHelp; pressedState = CaptionFlags.HelpPressed; } break; } if(pressed) { flags |= pressedState; } else { flags &= ~pressedState; } // Redraw the caption buttons to match the state change. if(flags != origFlags) { Rectangle rect = new Rectangle (FrameBorderSize, FrameBorderSize, width - FrameBorderSize * 2, captionHeight - FrameBorderSize); using(Graphics graphics = new Graphics(this)) { DrawCaptionButtons (graphics, rect, flags, buttonsToDraw); } } return ((origFlags & pressedState) != 0); }
// Adjust the child window to match the parent. public override void MoveResize(int x, int y, int width, int height) { flags |= CaptionFlags.InMoveResize; try { base.MoveResize(x, y, width, height); if(!(child.iconic)) { // Transmit the request to the X server. try { IntPtr display = dpy.Lock(); Xlib.XMoveResizeWindow (display, child.GetWidgetHandle(), FrameBorderSize, captionHeight, (uint)(width - FrameBorderSize * 2), (uint)(height - FrameBorderSize - captionHeight)); } finally { dpy.Unlock(); } // Transmit "OnMove" and "OnResize" events to the child. child.HandleMoveResize (x + FrameBorderSize, y + captionHeight, width - FrameBorderSize * 2, height - FrameBorderSize - captionHeight); } } finally { flags &= ~(CaptionFlags.InMoveResize); } }
// Make this caption widget active. internal void MakeActive() { // If we have a passive grab active, then remove it. if((flags & CaptionFlags.Grabbed) != 0) { try { IntPtr display = dpy.Lock(); Xlib.XUngrabButton (display, 0 /* AnyButton */, (1 << 15) /* AnyModifier */, GetWidgetHandle()); // We might have a frozen mouse pointer, so allow // events to proceed just in case. Xlib.XAllowEvents (display, 2 /* ReplayPointer */, dpy.knownEventTime); } finally { dpy.Unlock(); } flags &= ~CaptionFlags.Grabbed; } // Change the visual aspect of this window to active. flags |= CaptionFlags.Active; if(gradient != null) { gradient.Dispose(); gradient = null; } Repaint(); }
// Make this caption widget inactive. internal void MakeInactive() { // Add a passive grab so that we can intercept button // press events before the child window gets them // and cause the window to be raised first. if((flags & CaptionFlags.Grabbed) == 0) { try { IntPtr display = dpy.Lock(); Xlib.XGrabButton (display, 0 /* AnyButton */, (1 << 15) /* AnyModifier */, GetWidgetHandle(), XBool.False, (uint)(EventMask.ButtonPressMask), 0 /* GrabModeSync */, 1 /* GrabModeAsync */, XWindow.Zero, XCursor.Zero); } finally { dpy.Unlock(); } flags |= CaptionFlags.Grabbed; } // Change the visual aspect of this window to inactive. flags &= ~CaptionFlags.Active; if(gradient != null) { gradient.Dispose(); gradient = null; } Repaint(); }
// Update the window decorations to match the values on the child. private void UpdateDecorations() { CaptionFlags addFlags = (CaptionFlags)0; CaptionFlags removeFlags = (CaptionFlags)0; CaptionFlags newFlags; if(HasFunction(MotifFunctions.Close)) { addFlags |= CaptionFlags.HasClose; } else { removeFlags |= CaptionFlags.HasClose | CaptionFlags.ClosePressed; } if(!(child.IsIconic)) { if(HasFunction(MotifFunctions.Resize) && HasFunction(MotifFunctions.Maximize)) { if(child.IsMaximized) { addFlags |= CaptionFlags.HasRestore; removeFlags |= CaptionFlags.HasMaximize | CaptionFlags.MaximizePressed; } else { addFlags |= CaptionFlags.HasMaximize; removeFlags |= CaptionFlags.HasRestore | CaptionFlags.RestorePressed; } } else { removeFlags |= CaptionFlags.HasMaximize | CaptionFlags.MaximizePressed | CaptionFlags.HasRestore | CaptionFlags.RestorePressed; } if(HasFunction(MotifFunctions.Minimize)) { addFlags |= CaptionFlags.HasMinimize; } else { removeFlags |= CaptionFlags.HasMinimize | CaptionFlags.MinimizePressed; } } else { if(HasFunction(MotifFunctions.Maximize)) { addFlags |= CaptionFlags.HasRestore | CaptionFlags.HasMaximize; removeFlags |= CaptionFlags.HasMinimize | CaptionFlags.MinimizePressed; } else { addFlags |= CaptionFlags.HasRestore; removeFlags |= CaptionFlags.HasMaximize | CaptionFlags.MaximizePressed | CaptionFlags.HasMinimize | CaptionFlags.MinimizePressed; } } if((child.OtherHints & OtherHints.HelpButton) != 0) { addFlags |= CaptionFlags.HasHelp; } else { removeFlags |= CaptionFlags.HasHelp | CaptionFlags.HelpPressed; } newFlags = ((flags & ~removeFlags) | addFlags); if(newFlags != flags) { flags = newFlags; Repaint(); } }
// Construct a new caption widget underneath "parent", which // encapsulates the given "child" widget. public CaptionWidget(Widget parent, String name, int x, int y, int width, int height, Type type) : base(parent, x, y, width + FrameBorderSize * 2, height + GetCaptionHeight(parent) + FrameBorderSize, new Color(StandardColor.Foreground), new Color(StandardColor.Background)) { // Don't automatically map the child when it is created. AutoMapChildren = false; // Calculate the size of the caption, including the border. captionHeight = GetCaptionHeight(parent); // The caption widget is not focusable. Focusable = false; // Create the "top-level" window object for the child. ConstructorInfo ctor = type.GetConstructor (new Type [] {typeof(Widget), typeof(String), typeof(int), typeof(int), typeof(int), typeof(int)}); child = (TopLevelWindow)(ctor.Invoke (new Object[] {this, name, FrameBorderSize, captionHeight, width, height})); child.reparented = true; // Set the default flags. flags = CaptionFlags.HasClose | CaptionFlags.HasMaximize | CaptionFlags.HasMinimize; clickMode = HitTest.Outside; // Perform an initial move/resize to position the child // window properly within the MDI client area. MoveResize(this.x, this.y, this.width, this.height); // Make sure that we have the inactive grab. MakeInactive(); }