# HG changeset patch
# User Kit Yam Tse
# Date 1479858388 -39600
#      Wed Nov 23 10:46:28 2016 +1100
# Node ID 7a7ce769c97efed71770445e01344fada8ad6e82
# Parent  2a226d95a66d88d6b83815c6e97b5912b8023d8b
Implementation of MarginRightClick event.

diff --git a/cocoa/ScintillaCocoa.h b/cocoa/ScintillaCocoa.h
--- a/cocoa/ScintillaCocoa.h
+++ b/cocoa/ScintillaCocoa.h
@@ -213,6 +213,7 @@
 
   bool KeyboardInput(NSEvent* event);
   void MouseDown(NSEvent* event);
+  void RightMouseDown(NSEvent* event);
   void MouseMove(NSEvent* event);
   void MouseUp(NSEvent* event);
   void MouseEntered(NSEvent* event);
@@ -235,6 +236,8 @@
   virtual void Undo();
   virtual void Redo();
 
+  virtual bool ShouldDisplayPopupOnMargin();
+  virtual bool ShouldDisplayPopupOnText();
   virtual NSMenu* CreateContextMenu(NSEvent* event);
   void HandleCommand(NSInteger command);
 
diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm
--- a/cocoa/ScintillaCocoa.mm
+++ b/cocoa/ScintillaCocoa.mm
@@ -2455,6 +2455,17 @@
   ButtonDown(Point(location.x, location.y), (int) (time * 1000), shift, command, alt);
 }
 
+void ScintillaCocoa::RightMouseDown(NSEvent *event)
+{
+  Point location = ConvertPoint([event locationInWindow]);
+  NSTimeInterval time = [event timestamp];
+  bool command = ([event modifierFlags] & NSCommandKeyMask) != 0;
+  bool shift = ([event modifierFlags] & NSShiftKeyMask) != 0;
+  bool alt = ([event modifierFlags] & NSAlternateKeyMask) != 0;
+
+  RightButtonDownWithModifiers(Point(location.x, location.y), (int) (time * 1000), ModifierFlags(shift, command, alt));
+}
+
 //--------------------------------------------------------------------------------------------------
 
 void ScintillaCocoa::MouseMove(NSEvent* event)
@@ -2533,6 +2544,16 @@
 
 //--------------------------------------------------------------------------------------------------
 
+bool ScintillaCocoa::ShouldDisplayPopupOnMargin()
+{
+  return displayPopupMenu == SC_POPUP_ALL;
+}
+
+bool ScintillaCocoa::ShouldDisplayPopupOnText()
+{
+  return displayPopupMenu == SC_POPUP_ALL || displayPopupMenu == SC_POPUP_TEXT;
+}
+
 /**
  * Creates and returns a popup menu, which is then displayed by the Cocoa framework.
  */
diff --git a/cocoa/ScintillaView.mm b/cocoa/ScintillaView.mm
--- a/cocoa/ScintillaView.mm
+++ b/cocoa/ScintillaView.mm
@@ -116,6 +116,21 @@
   }
 }
 
+/**
+ * Called by the framework if it wants to show a context menu for the margin.
+ */
+- (NSMenu*) menuForEvent: (NSEvent*) theEvent
+{
+  NSMenu *menu = [owner menuForEvent: theEvent];
+  if (menu) {
+    return menu;
+  } else if (owner.backend->ShouldDisplayPopupOnMargin()) {
+    return owner.backend->CreateContextMenu(theEvent);
+  } else {
+    return nil;
+  }
+}
+
 - (void) mouseDown: (NSEvent *) theEvent
 {
   NSClipView *textView = [[self scrollView] contentView];
@@ -123,6 +138,13 @@
   owner.backend->MouseDown(theEvent);
 }
 
+- (void) rightMouseDown: (NSEvent *) theEvent
+{
+  [NSMenu popUpContextMenu:[self menuForEvent: theEvent] withEvent:theEvent forView:self];
+
+  owner.backend->RightMouseDown(theEvent);
+}
+
 - (void) mouseDragged: (NSEvent *) theEvent
 {
   owner.backend->MouseMove(theEvent);
@@ -380,10 +402,14 @@
  */
 - (NSMenu*) menuForEvent: (NSEvent*) theEvent
 {
-  if (![mOwner respondsToSelector: @selector(menuForEvent:)])
+  NSMenu *menu = [mOwner menuForEvent: theEvent];
+  if (menu) {
+    return menu;
+  } else if (mOwner.backend->ShouldDisplayPopupOnText()) {
     return mOwner.backend->CreateContextMenu(theEvent);
-  else
-    return [mOwner menuForEvent: theEvent];
+  } else {
+    return nil;
+  }
 }
 
 //--------------------------------------------------------------------------------------------------
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html
--- a/doc/ScintillaDoc.html
+++ b/doc/ScintillaDoc.html
@@ -3167,7 +3167,8 @@
     a visible margin will be displayed as changes in background colour in the text. A width in
     pixels can be set for each margin. Margins with a zero width are ignored completely. You can
     choose if a mouse click in a margin sends a <a class="message"
-    href="#SCN_MARGINCLICK"><code>SCN_MARGINCLICK</code></a> notification to the container or
+    href="#SCN_MARGINCLICK"><code>SCN_MARGINCLICK</code></a> or <a class="message"
+    href="#SCN_MARGINRIGHTCLICK"><code>SCN_MARGINRIGHTCLICK</code></a> notification to the container or
     selects a line of text.</p>
 
     <p>Using a margin number outside the valid range has no
@@ -3277,7 +3278,8 @@
      <b id="SCI_GETMARGINSENSITIVEN">SCI_GETMARGINSENSITIVEN(int margin) &rarr; bool</b><br />
      Each of the five margins can be set sensitive or insensitive to mouse clicks. A click in a
     sensitive margin sends a <a class="message"
-    href="#SCN_MARGINCLICK"><code>SCN_MARGINCLICK</code></a> <a class="jump"
+    href="#SCN_MARGINCLICK"><code>SCN_MARGINCLICK</code></a> or <a class="message"
+    href="#SCN_MARGINRIGHTCLICK"><code>SCN_MARGINRIGHTCLICK</code></a> <a class="jump"
     href="#Notifications">notification</a> to the container. Margins that are not sensitive act as
     selection margins which make it easy to select ranges of lines. By default, all margins are
     insensitive.</p>
@@ -5249,15 +5251,58 @@
 
     <h2 id="PopupEditMenu">Popup edit menu</h2>
 
-    <code><a class="message" href="#SCI_USEPOPUP">SCI_USEPOPUP(bool allowPopUp)</a><br />
+    <code><a class="message" href="#SCI_USEPOPUP">SCI_USEPOPUP(int displayPopUpMode)</a><br />
     </code>
 
-    <p><b id="SCI_USEPOPUP">SCI_USEPOPUP(bool allowPopUp)</b><br />
+    <p><b id="SCI_USEPOPUP">SCI_USEPOPUP(int popUpMode)</b><br />
      Clicking the wrong button on the mouse pops up a short default editing menu. This may be
-    turned off with <code>SCI_USEPOPUP(0)</code>. If you turn it off, context menu commands (in
+    turned off with <code>SCI_USEPOPUP(SC_POPUP_NEVER)</code>. If you turn it off, context menu commands (in
     Windows, <code>WM_CONTEXTMENU</code>) will not be handled by Scintilla, so the parent of the
     Scintilla window will have the opportunity to handle the message.</p>
 
+        <table cellpadding="1" cellspacing="2" border="0" summary="Display context menu mode">
+          <tbody>
+            <tr>
+              <th align="left">Symbol</th>
+
+              <th>Value</th>
+
+              <th align="left">Meaning</th>
+
+            </tr>
+          </tbody>
+
+          <tbody valign="top">
+            <tr>
+              <td align="left"><code>SC_POPUP_NEVER</code></td>
+
+              <td align="center">0x01</td>
+
+              <td>Never show default editing menu.</td>
+
+            </tr>
+
+            <tr>
+              <td align="left"><code>SC_POPUP_ALL</code></td>
+
+              <td align="center">0x02</td>
+
+              <td>Show default editing menu if clicking on scintilla.</td>
+
+            </tr>
+
+            <tr>
+              <td align="left"><code>SC_POPUP_TEXT</code></td>
+
+              <td align="center">0x04</td>
+
+              <td>Show default editing menu only if clicking on text area.</td>
+
+            </tr>
+
+          </tbody>
+        </table>
+
     <h2 id="MacroRecording">Macro recording</h2>
 
     <p>Start and stop macro recording mode. In macro recording mode, actions are reported to the
@@ -6757,9 +6802,9 @@
 	struct Sci_NotifyHeader nmhdr;
 	Sci_Position position;
 	/* SCN_STYLENEEDED, SCN_DOUBLECLICK, SCN_MODIFIED, SCN_MARGINCLICK, */
-	/* SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, SCN_CALLTIPCLICK, */
-	/* SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, SCN_HOTSPOTRELEASECLICK, */
-	/* SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
+	/* SCN_MARGINRIGHTCLICK, SCN_NEEDSHOWN, SCN_DWELLSTART, SCN_DWELLEND, */
+	/* SCN_CALLTIPCLICK, SCN_HOTSPOTCLICK, SCN_HOTSPOTDOUBLECLICK, */
+	/* SCN_HOTSPOTRELEASECLICK, SCN_INDICATORCLICK, SCN_INDICATORRELEASE, */
 	/* SCN_USERLISTSELECTION, SCN_AUTOCSELECTION */
 
 	int ch;
@@ -6781,7 +6826,7 @@
 	Sci_Position line;		/* SCN_MODIFIED */
 	int foldLevelNow;	/* SCN_MODIFIED */
 	int foldLevelPrev;	/* SCN_MODIFIED */
-	int margin;		/* SCN_MARGINCLICK */
+	int margin;		/* SCN_MARGINCLICK, SCN_MARGINRIGHTCLICK */
 	int listType;	/* SCN_USERLISTSELECTION */
 	int x;			/* SCN_DWELLSTART, SCN_DWELLEND */
 	int y;		/* SCN_DWELLSTART, SCN_DWELLEND */
@@ -6826,6 +6871,7 @@
      <a class="message" href="#SCN_FOCUSIN">SCN_FOCUSIN</a><br />
      <a class="message" href="#SCN_FOCUSOUT">SCN_FOCUSOUT</a><br />
      <a class="message" href="#SCN_AUTOCCOMPLETED">SCN_AUTOCCOMPLETED</a><br />
+     <a class="message" href="#SCN_MARGINRIGHTCLICK">SCN_MARGINRIGHTCLICK</a><br />
     </code>
 
     <p>The following <code>SCI_*</code> messages are associated with these notifications:</p>
@@ -7385,7 +7431,8 @@
     </table>
 
     <p><b id="SCN_MARGINCLICK">SCN_MARGINCLICK</b><br />
-     This notification tells the container that the mouse was clicked inside a <a class="jump"
+     <b id="SCN_MARGINRIGHTCLICK">SCN_MARGINRIGHTCLICK</b><br />
+     These notifications tell the container that the mouse was clicked or right clicked inside a <a class="jump"
     href="#Margins">margin</a> that was marked as sensitive (see <a class="message"
     href="#SCI_SETMARGINSENSITIVEN"><code>SCI_SETMARGINSENSITIVEN</code></a>). This can be used to
     perform folding or to place breakpoints. The following <code>SCNotification</code> fields are
diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx
--- a/gtk/ScintillaGTK.cxx
+++ b/gtk/ScintillaGTK.cxx
@@ -1703,7 +1703,7 @@
 		} else if (event->button == 3) {
 			if (!PointInSelection(pt))
 				SetEmptySelection(PositionFromLocation(pt));
-			if (displayPopupMenu) {
+			if (ShouldDisplayPopup(pt)) {
 				// PopUp menu
 				// Convert to screen
 				int ox = 0;
@@ -1711,7 +1711,15 @@
 				gdk_window_get_origin(PWindow(wMain), &ox, &oy);
 				ContextMenu(Point(pt.x + ox, pt.y + oy));
 			} else {
-				return FALSE;
+#if PLAT_GTK_MACOSX
+				bool meta = ctrl;
+				// GDK reports the Command modifer key as GDK_MOD2_MASK for button events,
+				// not GDK_META_MASK like in key events.
+				ctrl = (event->state & GDK_MOD2_MASK) != 0;
+#else
+				bool meta = false;
+#endif
+				RightButtonDownWithModifiers(pt, event->time, ModifierFlags(shift, ctrl, alt, meta));
 			}
 		} else if (event->button == 4) {
 			// Wheel scrolling up (only GTK 1.x does it this way)
diff --git a/include/Scintilla.h b/include/Scintilla.h
--- a/include/Scintilla.h
+++ b/include/Scintilla.h
@@ -673,6 +673,9 @@
 #define SCI_SEARCHNEXT 2367
 #define SCI_SEARCHPREV 2368
 #define SCI_LINESONSCREEN 2370
+#define SC_POPUP_NEVER 0
+#define SC_POPUP_ALL 1
+#define SC_POPUP_TEXT 2
 #define SCI_USEPOPUP 2371
 #define SCI_SELECTIONISRECTANGLE 2372
 #define SCI_SETZOOM 2373
@@ -1085,6 +1088,7 @@
 #define SCN_FOCUSIN 2028
 #define SCN_FOCUSOUT 2029
 #define SCN_AUTOCCOMPLETED 2030
+#define SCN_MARGINRIGHTCLICK 2031
 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */
 
 /* These structures are defined to be exactly the same shape as the Win32
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -1736,9 +1736,14 @@
 # Retrieves the number of lines completely visible.
 get int LinesOnScreen=2370(,)
 
+enu PopUp=SC_POPUP_
+val SC_POPUP_NEVER=0
+val SC_POPUP_ALL=1
+val SC_POPUP_TEXT=2
+
 # Set whether a pop up menu is displayed automatically when the user presses
-# the wrong mouse button.
-fun void UsePopUp=2371(bool allowPopUp,)
+# the wrong mouse button on certain areas.
+fun void UsePopUp=2371(int popUpMode,)
 
 # Is the selection rectangular? The alternative is the more common stream selection.
 get bool SelectionIsRectangle=2372(,)
@@ -4796,6 +4801,7 @@
 evt void FocusIn=2028(void)
 evt void FocusOut=2029(void)
 evt void AutoCCompleted=2030(string text, int position, int ch, CompletionMethods listCompletionMethod)
+evt void MarginRightClick=2031(int modifiers, int position, int margin)
 
 # There are no provisional APIs currently, but some arguments to SCI_SETTECHNOLOGY are provisional.
 
diff --git a/qt/ScintillaEditBase/ScintillaEditBase.cpp b/qt/ScintillaEditBase/ScintillaEditBase.cpp
--- a/qt/ScintillaEditBase/ScintillaEditBase.cpp
+++ b/qt/ScintillaEditBase/ScintillaEditBase.cpp
@@ -289,9 +289,7 @@
 		return;
 	}
 
-	bool button = event->button() == Qt::LeftButton;
-
-	if (button) {
+	if (event->button() == Qt::LeftButton) {
 		bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
 		bool ctrl  = QApplication::keyboardModifiers() & Qt::ControlModifier;
 #ifdef Q_WS_X11
@@ -304,6 +302,14 @@
 
 		sqt->ButtonDown(pos, time.elapsed(), shift, ctrl, alt);
 	}
+
+	if (event->button() == Qt::RightButton) {
+		bool shift = QApplication::keyboardModifiers() & Qt::ShiftModifier;
+		bool ctrl  = QApplication::keyboardModifiers() & Qt::ControlModifier;
+		bool alt   = QApplication::keyboardModifiers() & Qt::AltModifier;
+
+		sqt->RightButtonDownWithModifiers(pos, time.elapsed(), ScintillaQt::ModifierFlags(shift, ctrl, alt));
+	}
 }
 
 void ScintillaEditBase::mouseReleaseEvent(QMouseEvent *event)
@@ -350,9 +356,12 @@
 {
 	Point pos = PointFromQPoint(event->globalPos());
 	Point pt = PointFromQPoint(event->pos());
-	if (!sqt->PointInSelection(pt))
+	if (!sqt->PointInSelection(pt)) {
 		sqt->SetEmptySelection(sqt->PositionFromLocation(pt));
-	sqt->ContextMenu(pos);
+	}
+	if (sqt->ShouldDisplayPopup(pt)) {
+		sqt->ContextMenu(pos);
+	}
 }
 
 void ScintillaEditBase::dragEnterEvent(QDragEnterEvent *event)
diff --git a/src/Editor.cxx b/src/Editor.cxx
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -2465,6 +2465,22 @@
 	return NotifyMarginClick(pt, ModifierFlags(shift, ctrl, alt));
 }
 
+bool Editor::NotifyMarginRightClick(Point pt, int modifiers) {
+	int marginRightClicked = vs.MarginFromLocation(pt);
+	if ((marginRightClicked >= 0) && vs.ms[marginRightClicked].sensitive) {
+		int position = pdoc->LineStart(LineFromLocation(pt));
+		SCNotification scn = {};
+		scn.nmhdr.code = SCN_MARGINRIGHTCLICK;
+		scn.modifiers = modifiers;
+		scn.position = position;
+		scn.margin = marginRightClicked;
+		NotifyParent(scn);
+		return true;
+	} else {
+		return false;
+	}
+}
+
 void Editor::NotifyNeedShown(int pos, int len) {
 	SCNotification scn = {};
 	scn.nmhdr.code = SCN_NEEDSHOWN;
@@ -4578,6 +4594,11 @@
 	ShowCaretAtCurrentPosition();
 }
 
+void Editor::RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) {
+	if (NotifyMarginRightClick(pt, modifiers))
+		return;
+}
+
 void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {
 	return ButtonDownWithModifiers(pt, curTime, ModifierFlags(shift, ctrl, alt));
 }
diff --git a/src/Editor.h b/src/Editor.h
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -439,6 +439,7 @@
 	void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt);
 	bool NotifyMarginClick(Point pt, int modifiers);
 	bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt);
+	bool NotifyMarginRightClick(Point pt, int modifiers);
 	void NotifyNeedShown(int pos, int len);
 	void NotifyDwelling(Point pt, bool state);
 	void NotifyZoom();
@@ -508,6 +509,7 @@
 	void DwellEnd(bool mouseMoved);
 	void MouseLeave();
 	virtual void ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers);
+	virtual void RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers);
 	virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt);
 	void ButtonMoveWithModifiers(Point pt, int modifiers);
 	void ButtonMove(Point pt);
diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx
--- a/src/ScintillaBase.cxx
+++ b/src/ScintillaBase.cxx
@@ -64,7 +64,7 @@
 #endif
 
 ScintillaBase::ScintillaBase() {
-	displayPopupMenu = true;
+	displayPopupMenu = SC_POPUP_ALL;
 	listType = 0;
 	maxListWidth = 0;
 	multiAutoCMode = SC_MULTIAUTOC_ONCE;
@@ -478,6 +478,11 @@
 	NotifyParent(scn);
 }
 
+bool ScintillaBase::ShouldDisplayPopup(Point ptInWindowCoordinates) {
+	return (displayPopupMenu == SC_POPUP_ALL ||
+		(displayPopupMenu == SC_POPUP_TEXT && !PointInSelMargin(ptInWindowCoordinates)));
+}
+
 void ScintillaBase::ContextMenu(Point pt) {
 	if (displayPopupMenu) {
 		bool writable = !WndProc(SCI_GETREADONLY, 0, 0);
@@ -510,6 +515,11 @@
 	ButtonDownWithModifiers(pt, curTime, ModifierFlags(shift, ctrl, alt));
 }
 
+void ScintillaBase::RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers) {
+	CancelModes();
+	Editor::RightButtonDownWithModifiers(pt, curTime, modifiers);
+}
+
 #ifdef SCI_LEXER
 
 #ifdef SCI_NAMESPACE
@@ -970,7 +980,7 @@
 		break;
 
 	case SCI_USEPOPUP:
-		displayPopupMenu = wParam != 0;
+		displayPopupMenu = static_cast<int>(wParam);
 		break;
 
 #ifdef SCI_LEXER
diff --git a/src/ScintillaBase.h b/src/ScintillaBase.h
--- a/src/ScintillaBase.h
+++ b/src/ScintillaBase.h
@@ -40,7 +40,7 @@
 
 	enum { maxLenInputIME = 200 };
 
-	bool displayPopupMenu;
+	int displayPopupMenu;
 	Menu popup;
 	AutoComplete ac;
 
@@ -84,10 +84,12 @@
 	virtual void CreateCallTipWindow(PRectangle rc) = 0;
 
 	virtual void AddToPopUp(const char *label, int cmd=0, bool enabled=true) = 0;
+	bool ShouldDisplayPopup(Point ptInWindowCoordinates);
 	void ContextMenu(Point pt);
 
 	virtual void ButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers);
 	virtual void ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt);
+	virtual void RightButtonDownWithModifiers(Point pt, unsigned int curTime, int modifiers);
 
 	void NotifyStyleToNeeded(int endStyleNeeded);
 	void NotifyLexerChanged(Document *doc, void *userData);
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -1418,12 +1418,18 @@
 				(wParam & MK_CONTROL) != 0);
 			break;
 
-		case WM_RBUTTONDOWN:
+		case WM_RBUTTONDOWN: {
 			::SetFocus(MainHWND());
-			if (!PointInSelection(Point::FromLong(static_cast<long>(lParam)))) {
+			Point pt = Point::FromLong(static_cast<long>(lParam));
+			if (!PointInSelection(pt)) {
 				CancelModes();
 				SetEmptySelection(PositionFromLocation(Point::FromLong(static_cast<long>(lParam))));
 			}
+
+			RightButtonDownWithModifiers(pt, ::GetMessageTime(), ModifierFlags((wParam & MK_SHIFT) != 0,
+			                                                      (wParam & MK_CONTROL) != 0,
+			                                                      Platform::IsKeyDown(VK_MENU)));
+			}
 			break;
 
 		case WM_SETCURSOR:
@@ -1572,8 +1578,10 @@
 			}
 
 		case WM_CONTEXTMENU:
-			if (displayPopupMenu) {
-				Point pt = Point::FromLong(static_cast<long>(lParam));
+			Point pt = Point::FromLong(static_cast<long>(lParam));
+			POINT rpt = {static_cast<int>(pt.x), static_cast<int>(pt.y)};
+			::ScreenToClient(MainHWND(), &rpt);
+			if (ShouldDisplayPopup(rpt)) {
 				if ((pt.x == -1) && (pt.y == -1)) {
 					// Caused by keyboard so display menu near caret
 					pt = PointMainCaret();
