You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
motif/SOURCES/0002-Xm-Display-Add-optiona...

420 lines
11 KiB

From 011e62e69fb87e78a128487a043cc13b042bb8b5 Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <ofourdan@redhat.com>
Date: Wed, 20 Nov 2024 10:26:28 +0100
Subject: [PATCH 2/7] Xm/Display: Add optional Xinerama support
Xinerama support is disabled by default, unless the Xresource
"enableXinerama" is set in the X resources database, e.g.:
*enableXinerama: True
This also provides an additional private Screen API to get the monitor
boundaries given a point on screen. This is meant to be used in the
following commits to implement Xinerama awareness in the relevant
widgets.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
---
doc/man/man3/XmDisplay.3 | 2 +
lib/Xm/Display.c | 95 +++++++++++++++++++++++++++++
lib/Xm/DisplayP.h | 18 ++++++
lib/Xm/Screen.c | 128 +++++++++++++++++++++++++++++++++++++++
lib/Xm/ScreenP.h | 8 +++
lib/Xm/xmstring.list.in | 2 +
6 files changed, 253 insertions(+)
diff --git a/doc/man/man3/XmDisplay.3 b/doc/man/man3/XmDisplay.3
index a57ea089..ec360c80 100644
--- a/doc/man/man3/XmDisplay.3
+++ b/doc/man/man3/XmDisplay.3
@@ -158,6 +158,8 @@ XmNnoRenditionCallbackXmCCallbackXtCallbackListNULLC
_____
XmNuserDataXmCUserDataXtPointerNULLCSG
_____
+XmNenableXineramaXmCEnableXineramaBooleanFalseC
+_____
.TE
.IP "\fBXmNdefaultButtonEmphasis\fP" 10
Specifies whether to change the look of the PushButton widget and
diff --git a/lib/Xm/Display.c b/lib/Xm/Display.c
index 55fe4cd3..3ab047f2 100644
--- a/lib/Xm/Display.c
+++ b/lib/Xm/Display.c
@@ -35,6 +35,9 @@ static char rcsid[] = "$TOG: Display.c /main/23 1997/06/18 17:36:59 samborn $"
#include <X11/Intrinsic.h>
#include <X11/extensions/shape.h>
+#ifdef HAVE_LIBXINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
#include <X11/Xatom.h>
#include <Xm/AtomMgr.h>
@@ -273,6 +276,13 @@ static XtResource resources[] = {
XtOffsetOf(WMShellRec, wm.wm_hints.icon_pixmap),
XmRImmediate, NULL
},
+ /* Xinerama support */
+ {
+ XmNenableXinerama, XmCEnableXinerama,
+ XmRBoolean, sizeof(Boolean),
+ Offset(display.enable_xinerama),
+ XmRImmediate, (XtPointer) False
+ },
};
#undef Offset
@@ -388,6 +398,45 @@ DisplayClassInitialize( void )
XmMakeCanonicalString("_MOTIF_DRAG_AND_DROP_MESSAGE");
}
+static void
+DisplayInitializeXinerama( XmDisplay xmDisplay )
+{
+#ifdef HAVE_LIBXINERAMA
+ Display *display = XtDisplay(xmDisplay);
+ int dummy1, dummy2;
+ Status have_xinerama;
+
+ xmDisplay->display.monitors = NULL;
+ xmDisplay->display.n_monitors = 0;
+
+ /* Xinerama support is disabled by default, unless XmNenableXinerama is set */
+ if (!xmDisplay->display.enable_xinerama) {
+#ifdef DEBUG_XINERAMA
+ printf("XINERAMA support not enabled\n");
+#endif /* DEBUG_XINERAMA */
+ return;
+ }
+
+ if (!XineramaQueryExtension(display, &dummy1, &dummy2)) {
+#ifdef DEBUG_XINERAMA
+ printf("XINERAMA extension not available\n");
+#endif /* DEBUG_XINERAMA */
+ xmDisplay->display.enable_xinerama = False;
+ return;
+ }
+
+ if (!XineramaIsActive(display)) {
+#ifdef DEBUG_XINERAMA
+ printf("XINERAMA extension not activated\n");
+#endif /* DEBUG_XINERAMA */
+ xmDisplay->display.enable_xinerama = False;
+ return;
+ }
+
+ _XmDisplayUpdateXinerama(xmDisplay);
+#endif /* HAVE_LIBXINERAMA */
+}
+
/*ARGSUSED*/
static void
SetDragReceiverInfo(
@@ -553,6 +602,8 @@ DisplayInitialize(
XmDRAG_PREFER_PREREGISTER;
}
+ DisplayInitializeXinerama(xmDisplay);
+
_XmVirtKeysInitialize (new_widget);
_XmProcessLock();
@@ -672,6 +723,9 @@ DisplayDestroy(
_XmVirtKeysDestroy (w);
+#ifdef HAVE_LIBXINERAMA
+ XFree(dd->display.monitors);
+#endif /* HAVE_LIBXINERAMA */
XDeleteContext( XtDisplay( w), None, context) ;
}
@@ -1225,3 +1279,44 @@ _XmSetThicknessDefault0(
value->addr = (XPointer)&thickness;
}
+
+
+Boolean
+_XmDisplayUseXinerama(
+ XmDisplay xmDisplay )
+{
+ return xmDisplay && xmDisplay->display.enable_xinerama;
+}
+
+
+void
+_XmDisplayUpdateXinerama(
+ XmDisplay xmDisplay )
+{
+#ifdef HAVE_LIBXINERAMA
+#ifdef DEBUG_XINERAMA
+ int i;
+#endif /* DEBUG_XINERAMA */
+
+ if (!_XmDisplayUseXinerama(xmDisplay))
+ return;
+
+#ifdef DEBUG_XINERAMA
+ printf("Updating XINERAMA configuration\n");
+#endif /* DEBUG_XINERAMA */
+
+ if (xmDisplay->display.monitors)
+ XFree(xmDisplay->display.monitors);
+
+ xmDisplay->display.monitors =
+ XineramaQueryScreens (XtDisplay(xmDisplay), &xmDisplay->display.n_monitors);
+
+#ifdef DEBUG_XINERAMA
+ for (i = 0; i < xmDisplay->display.n_monitors; ++i) {
+ printf("XINERAMA Monitor %i: (%i,%i) [%ix%i]\n", i,
+ xmDisplay->display.monitors[i].x_org, xmDisplay->display.monitors[i].y_org,
+ xmDisplay->display.monitors[i].width, xmDisplay->display.monitors[i].height);
+ }
+#endif /* DEBUG_XINERAMA */
+#endif /* HAVE_LIBXINERAMA */
+}
diff --git a/lib/Xm/DisplayP.h b/lib/Xm/DisplayP.h
index 655c29b6..a2420f96 100644
--- a/lib/Xm/DisplayP.h
+++ b/lib/Xm/DisplayP.h
@@ -23,6 +23,14 @@
#ifndef _XmDisplayP_h
#define _XmDisplayP_h
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LIBXINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
#include <Xm/DesktopP.h>
#include <Xm/VendorSEP.h>
#include <Xm/DropSMgr.h>
@@ -115,6 +123,11 @@ typedef struct {
Boolean enable_unselectable_drag;
Boolean enable_thin_thickness;
Boolean enable_multi_key_bindings;
+ Boolean enable_xinerama;
+#ifdef HAVE_LIBXINERAMA
+ XineramaScreenInfo *monitors;
+ int n_monitors;
+#endif
} XmDisplayPart, *XmDisplayPartPtr;
typedef struct _XmDisplayInfo {
@@ -143,6 +156,11 @@ externalref XmDisplayClassRec xmDisplayClassRec;
externalref String _Xm_MOTIF_DRAG_AND_DROP_MESSAGE ;
+extern Boolean _XmDisplayUseXinerama(
+ XmDisplay xmDisplay ) ;
+
+extern void _XmDisplayUpdateXinerama(
+ XmDisplay xmDisplay ) ;
#ifdef __cplusplus
} /* Close scope of 'extern "C"' declaration which encloses file. */
diff --git a/lib/Xm/Screen.c b/lib/Xm/Screen.c
index 10ba8d2b..44abcfb3 100644
--- a/lib/Xm/Screen.c
+++ b/lib/Xm/Screen.c
@@ -396,7 +396,67 @@ GetUnitFromFont(
}
}
+#ifdef HAVE_LIBXINERAMA
+/* ARGSUSED */
+static void
+StructureNotifyHandler(
+ Widget wid,
+ XtPointer data,
+ XEvent *event,
+ Boolean *cont )
+{
+ Display *display = XtDisplay(wid);
+
+#ifdef DEBUG_XINERAMA
+ printf("Root event received\n");
+#endif /* DEBUG_XINERAMA */
+ if (event->type == ConfigureNotify)
+ _XmDisplayUpdateXinerama((XmDisplay) XmGetXmDisplay(display)) ;
+}
+
+/* ARGSUSED */
+static void
+InstallStructureNotifyHandler(
+ XmScreen xmScreen)
+{
+ Display *display = XtDisplay(xmScreen);
+ Window rootwindow;
+ XWindowAttributes rootattributes;
+
+ if (!_XmDisplayUseXinerama((XmDisplay) XmGetXmDisplay(display)))
+ return;
+
+ rootwindow = RootWindowOfScreen(XtScreen(xmScreen));
+ XGetWindowAttributes(display, rootwindow, &rootattributes);
+ XSelectInput(display,
+ rootwindow,
+ StructureNotifyMask | rootattributes.your_event_mask);
+ XtRegisterDrawable(display, rootwindow, (Widget)xmScreen);
+ XtAddEventHandler((Widget)xmScreen,
+ (EventMask) StructureNotifyMask, True,
+ StructureNotifyHandler, (XtPointer) NULL);
+}
+
+/* ARGSUSED */
+static void
+UninstallStructureNotifyHandler(
+ XmScreen xmScreen)
+{
+ Display *display = XtDisplay(xmScreen);
+ Window rootwindow;
+ XWindowAttributes rootattributes;
+
+ if (!_XmDisplayUseXinerama((XmDisplay) XmGetXmDisplay(display)))
+ return;
+
+ rootwindow = RootWindowOfScreen(XtScreen(xmScreen));
+ XtUnregisterDrawable(display, rootwindow);
+ XtRemoveEventHandler((Widget)xmScreen,
+ (EventMask) StructureNotifyMask, True,
+ StructureNotifyHandler, (XtPointer) NULL);
+}
+#endif /* HAVE_LIBXINERAMA */
/************************************************************************
*
@@ -413,6 +473,8 @@ Initialize(
{
XmScreen xmScreen = (XmScreen)new_widget;
Display *display = XtDisplay(new_widget);
+ Window rootwindow;
+ XWindowAttributes rootattributes;
xmScreen->screen.screenInfo = NULL;
@@ -474,6 +536,9 @@ Initialize(
}
#endif
+#ifdef HAVE_LIBXINERAMA
+ InstallStructureNotifyHandler(xmScreen);
+#endif /* HAVE_LIBXINERAMA */
}
/************************************************************************
@@ -672,6 +737,10 @@ Destroy(
/* need to remove pixmap and GC related to this screen */
_XmCleanPixmapCache (XtScreen(widget), NULL);
+
+#ifdef HAVE_LIBXINERAMA
+ UninstallStructureNotifyHandler(xmScreen);
+#endif /* HAVE_LIBXINERAMA */
}
static void
@@ -1447,3 +1516,62 @@ XmGetXmScreen(
_XmAppUnlock(app);
return widget;
}
+
+void
+_XmScreenGetBoundariesAtpoint(
+ Screen *screen,
+ Position pt_x,
+ Position pt_y,
+ Position *ret_x,
+ Position *ret_y,
+ Position *ret_max_x,
+ Position *ret_max_y )
+{
+ XmDisplay xmDisplay;
+ Position screen_x, screen_y;
+ Position screen_max_x, screen_max_y;
+#ifdef HAVE_LIBXINERAMA
+ Position tmp_x, tmp_y;
+ Position tmp_max_x, tmp_max_y;
+ int i;
+#endif /* HAVE_LIBXINERAMA */
+
+ xmDisplay = (XmDisplay) XmGetXmDisplay(DisplayOfScreen(screen));
+ screen_x = 0;
+ screen_y = 0;
+ screen_max_x = WidthOfScreen(screen);
+ screen_max_y = HeightOfScreen(screen);
+
+ if (!_XmDisplayUseXinerama(xmDisplay))
+ goto out;
+
+#ifdef HAVE_LIBXINERAMA
+ for (i = 0; i < xmDisplay->display.n_monitors; ++i) {
+ tmp_x = xmDisplay->display.monitors[i].x_org;
+ tmp_y = xmDisplay->display.monitors[i].y_org;
+ tmp_max_x = tmp_x + xmDisplay->display.monitors[i].width;
+ tmp_max_y = tmp_y + xmDisplay->display.monitors[i].height;
+
+ if (pt_x >= tmp_x && pt_x < tmp_max_x && pt_y >= tmp_y && pt_y < tmp_max_y) {
+ screen_x = tmp_x;
+ screen_y = tmp_y;
+ screen_max_x = tmp_max_x;
+ screen_max_y = tmp_max_y;
+ break; /* We have a match */
+ }
+ }
+#endif /* HAVE_LIBXINERAMA */
+out:
+#ifdef DEBUG_XINERAMA
+ printf("Point (%i,%i) constrained within (%i,%i) and (%i,%i)\n",
+ pt_x, pt_y, screen_x, screen_y, screen_max_x, screen_max_y);
+#endif /* DEBUG_XINERAMA */
+ if (ret_x)
+ *ret_x = screen_x;
+ if (ret_y)
+ *ret_y = screen_y;
+ if (ret_max_x)
+ *ret_max_x = screen_max_x;
+ if (ret_max_y)
+ *ret_max_y = screen_max_y;
+}
diff --git a/lib/Xm/ScreenP.h b/lib/Xm/ScreenP.h
index c870c19e..b4b95a6f 100644
--- a/lib/Xm/ScreenP.h
+++ b/lib/Xm/ScreenP.h
@@ -134,6 +134,14 @@ typedef struct _XmScreenRec {
XmScreenPart screen;
} XmScreenRec;
+extern void _XmScreenGetBoundariesAtpoint(
+ Screen *screen,
+ Position pt_x,
+ Position pt_y,
+ Position *ret_x,
+ Position *ret_y,
+ Position *ret_max_x,
+ Position *ret_max_y ) ;
#ifdef __cplusplus
} /* Close scope of 'extern "C"' declaration which encloses file. */
diff --git a/lib/Xm/xmstring.list.in b/lib/Xm/xmstring.list.in
index 8c0c4f9a..5887e7ad 100644
--- a/lib/Xm/xmstring.list.in
+++ b/lib/Xm/xmstring.list.in
@@ -1692,6 +1692,8 @@ CFontEncoding
NxftFont
CXftFont
SUTF8_STRING
+NenableXinerama
+CEnableXinerama
#file XmStrDefsI.h
#table _XmStringsI
--
2.47.1