mirror of
https://gitee.com/csharpui/CPF.git
synced 2026-06-27 06:43:09 +08:00
初始化
This commit is contained in:
377
CPF.Linux/NotifyIcon.cs
Normal file
377
CPF.Linux/NotifyIcon.cs
Normal file
@@ -0,0 +1,377 @@
|
||||
using CPF.Controls;
|
||||
using CPF.Drawing;
|
||||
using CPF.Input;
|
||||
using CPF.Platform;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static CPF.Linux.XLib;
|
||||
|
||||
namespace CPF.Linux
|
||||
{
|
||||
class NotifyIcon : XWindow, INotifyIconImpl
|
||||
{
|
||||
public NotifyIcon()
|
||||
{
|
||||
DisplayHandle = LinuxPlatform.Platform.Display;
|
||||
}
|
||||
LinuxPlatform x11info;
|
||||
|
||||
XSetWindowAttributes attr = new XSetWindowAttributes();
|
||||
protected override void OnCreateWindw()
|
||||
{
|
||||
x11info = LinuxPlatform.Platform;
|
||||
var valueMask = default(SetWindowValuemask);
|
||||
attr.background_pixel = IntPtr.Zero;
|
||||
attr.border_pixel = IntPtr.Zero;
|
||||
attr.backing_store = 1;
|
||||
attr.bit_gravity = Gravity.NorthWestGravity;
|
||||
attr.win_gravity = Gravity.NorthWestGravity;
|
||||
attr.override_redirect = true;
|
||||
valueMask |= SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel | SetWindowValuemask.BackingStore | SetWindowValuemask.OverrideRedirect
|
||||
//| SetWindowValuemask.BackPixmap
|
||||
| SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
|
||||
valueMask |= SetWindowValuemask.SaveUnder;
|
||||
|
||||
attr.colormap = XLib.XCreateColormap(x11info.Info.Display, x11info.Info.RootWindow, x11info.Info.TransparentVisualInfo.visual, 0);
|
||||
valueMask |= SetWindowValuemask.ColorMap;
|
||||
|
||||
Handle = XLib.XCreateWindow(x11info.Display, x11info.Info.DefaultRootWindow, 0, 0, 16, 16, 0, 32, (int)CreateWindowArgs.InputOutput, x11info.Info.TransparentVisualInfo.visual, new UIntPtr((uint)valueMask), ref attr);
|
||||
//Handle= XCreateSimpleWindow(x11info.Display, x11info.Info.DefaultRootWindow, 0, 0, 16, 16, 0, IntPtr.Zero, XWhitePixel(x11info.Display,x11info.Info.DefaultScreen));
|
||||
|
||||
XEventMask ignoredMask = XEventMask.SubstructureRedirectMask | XEventMask.ResizeRedirectMask | XEventMask.PointerMotionHintMask;
|
||||
var mask = new IntPtr(0xffffff ^ (int)ignoredMask);
|
||||
XLib.XSelectInput(x11info.Display, Handle, mask);
|
||||
EventAction = OnXEvent;
|
||||
popup.Children.Add(textBlock);
|
||||
}
|
||||
Bitmap bitmap;
|
||||
void OnXEvent(ref XEvent ev)
|
||||
{
|
||||
if (ev.type == XEventName.Expose)
|
||||
{
|
||||
XWindowAttributes Attr = new XWindowAttributes();
|
||||
XGetWindowAttributes(DisplayHandle, Handle, ref Attr);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
if (bitmap == null || bitmap.Width != Attr.width || bitmap.Height != Attr.height)
|
||||
{
|
||||
if (bitmap != null)
|
||||
{
|
||||
bitmap.Dispose();
|
||||
}
|
||||
bitmap = new Bitmap(Attr.width, Attr.height);
|
||||
}
|
||||
using (var dc = DrawingContext.FromBitmap(bitmap))
|
||||
{
|
||||
dc.AntialiasMode = AntialiasMode.AntiAlias;
|
||||
dc.Clear(Color.Transparent);
|
||||
dc.DrawImage(icon, new Rect(0, 0, bitmap.Width, bitmap.Height), new Rect(0, 0, icon.Width, icon.Height));
|
||||
}
|
||||
}
|
||||
if (bitmap != null)
|
||||
{
|
||||
using (var l = bitmap.Lock())
|
||||
{
|
||||
var gc = XCreateGC(x11info.Display, Handle, 0, IntPtr.Zero);
|
||||
//XLockDisplay(x11info.Display);
|
||||
var img = new XImage();
|
||||
int bitsPerPixel = 32;
|
||||
img.width = bitmap.Width;
|
||||
img.height = bitmap.Height;
|
||||
img.format = 2; //ZPixmap;
|
||||
img.data = l.DataPointer;
|
||||
img.byte_order = 0;// LSBFirst;
|
||||
img.bitmap_unit = bitsPerPixel;
|
||||
img.bitmap_bit_order = 0;// LSBFirst;
|
||||
img.bitmap_pad = bitsPerPixel;
|
||||
img.depth = 32;
|
||||
img.bytes_per_line = bitmap.Width * 4;
|
||||
img.bits_per_pixel = bitsPerPixel;
|
||||
XInitImage(ref img);
|
||||
|
||||
XPutImage(x11info.Display, Handle, gc, ref img, 0, 0, 0, 0, (uint)Attr.width, (uint)Attr.height);
|
||||
//XSync(x11info.Display, false);
|
||||
//XUnlockDisplay(x11info.Display);
|
||||
XFreeGC(x11info.Display, gc);
|
||||
//XFlush(x11info.Display);
|
||||
//Console.WriteLine(Attr.width + "," + Attr.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ev.type == XEventName.ButtonPress)
|
||||
{
|
||||
if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9)
|
||||
{
|
||||
MouseButton mouseButton = MouseButton.None;
|
||||
switch (ev.ButtonEvent.button)
|
||||
{
|
||||
case 1:
|
||||
mouseButton = MouseButton.Left;
|
||||
break;
|
||||
case 2:
|
||||
mouseButton = MouseButton.Middle;
|
||||
break;
|
||||
case 3:
|
||||
mouseButton = MouseButton.Right;
|
||||
break;
|
||||
case 8:
|
||||
mouseButton = MouseButton.XButton1;
|
||||
break;
|
||||
case 9:
|
||||
mouseButton = MouseButton.XButton2;
|
||||
break;
|
||||
}
|
||||
if (MouseDown != null)
|
||||
{
|
||||
MouseDown(this, new NotifyIconMouseEventArgs(mouseButton));
|
||||
}
|
||||
if (mouseButton == MouseButton.Left)
|
||||
{
|
||||
var time = DateTime.Now;
|
||||
if (mouseDownTime.HasValue)
|
||||
{
|
||||
if (time - mouseDownTime <= LinuxPlatform.Platform.DoubleClickTime)
|
||||
{
|
||||
if (DoubleClick != null)
|
||||
{
|
||||
DoubleClick(this, EventArgs.Empty);
|
||||
}
|
||||
mouseDownTime = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseDownTime = time;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseDownTime = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ev.type == XEventName.ButtonRelease)
|
||||
{
|
||||
if (ev.ButtonEvent.button < 4 || ev.ButtonEvent.button == 8 || ev.ButtonEvent.button == 9)
|
||||
{
|
||||
MouseButton mouseButton = MouseButton.None;
|
||||
switch (ev.ButtonEvent.button)
|
||||
{
|
||||
case 1:
|
||||
mouseButton = MouseButton.Left;
|
||||
break;
|
||||
case 2:
|
||||
mouseButton = MouseButton.Middle;
|
||||
break;
|
||||
case 3:
|
||||
mouseButton = MouseButton.Right;
|
||||
break;
|
||||
case 8:
|
||||
mouseButton = MouseButton.XButton1;
|
||||
break;
|
||||
case 9:
|
||||
mouseButton = MouseButton.XButton2;
|
||||
break;
|
||||
}
|
||||
if (MouseUp != null)
|
||||
{
|
||||
MouseUp(this, new NotifyIconMouseEventArgs(mouseButton));
|
||||
}
|
||||
if (mouseButton == MouseButton.Left)
|
||||
{
|
||||
if (Click != null)
|
||||
{
|
||||
Click(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ev.type == XEventName.MotionNotify)
|
||||
{
|
||||
if (!isMouseEnter)
|
||||
{
|
||||
isMouseEnter = true;
|
||||
if (!string.IsNullOrWhiteSpace(Text))
|
||||
{
|
||||
textBlock.Text = Text;
|
||||
popup.Placement = PlacementMode.Absolute;
|
||||
var p = MouseDevice.Location;
|
||||
popup.MarginLeft = p.X / popup.LayoutScaling + 10;
|
||||
if (p.X < 100)
|
||||
{
|
||||
popup.MarginTop = p.Y / popup.LayoutScaling + 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
popup.MarginTop = p.Y / popup.LayoutScaling - 30;
|
||||
}
|
||||
popup.LoadStyle(Window.Windows.FirstOrDefault(a => a.IsMain));
|
||||
popup.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ev.type == XEventName.LeaveNotify)
|
||||
{
|
||||
isMouseEnter = false;
|
||||
if (popup.Visibility == Visibility.Visible)
|
||||
{
|
||||
popup.Width = "auto";
|
||||
popup.Height = "auto";
|
||||
popup.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
TextBlock textBlock = new TextBlock { Margin = "2" };
|
||||
Popup popup = new Popup
|
||||
{
|
||||
CanActivate = false,
|
||||
StaysOpen = false,
|
||||
BorderFill = "#aaa",
|
||||
Background = "#fff",
|
||||
BorderStroke = "1",
|
||||
};
|
||||
bool isMouseEnter;
|
||||
IntPtr DisplayHandle;
|
||||
IntPtr SystrayMgrWindow;
|
||||
|
||||
public string Text { get; set; }
|
||||
Image icon;
|
||||
public Image Icon
|
||||
{
|
||||
get { return icon; }
|
||||
set
|
||||
{
|
||||
icon = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void Invalidate()
|
||||
{
|
||||
XWindowAttributes Attr = new XWindowAttributes();
|
||||
XGetWindowAttributes(DisplayHandle, Handle, ref Attr);
|
||||
var xev = new XEvent
|
||||
{
|
||||
ExposeEvent =
|
||||
{
|
||||
type = XEventName.Expose,
|
||||
send_event = true,
|
||||
window = Handle,
|
||||
count=1,
|
||||
display=x11info.Display,
|
||||
height=Attr.height,
|
||||
width= Attr.width,
|
||||
}
|
||||
};
|
||||
lock (XlibLock)
|
||||
{
|
||||
XSendEvent(x11info.Display, Handle, false,
|
||||
new IntPtr((int)(EventMask.ExposureMask)), ref xev);
|
||||
}
|
||||
}
|
||||
|
||||
//public ContextMenu ContextMenu { get; set; }
|
||||
|
||||
bool visible;
|
||||
DateTime? mouseDownTime;
|
||||
public event EventHandler Click;
|
||||
public event EventHandler DoubleClick;
|
||||
public event EventHandler<NotifyIconMouseEventArgs> MouseDown;
|
||||
public event EventHandler<NotifyIconMouseEventArgs> MouseUp;
|
||||
|
||||
bool maped;
|
||||
public bool Visible
|
||||
{
|
||||
get { return visible; }
|
||||
set
|
||||
{
|
||||
//System.Threading.Thread.Sleep(10000);
|
||||
visible = value;
|
||||
if (visible)
|
||||
{
|
||||
XGrabServer(DisplayHandle);
|
||||
SystrayMgrWindow = XGetSelectionOwner(DisplayHandle, LinuxPlatform.Platform.Info.Atoms._NET_SYSTEM_TRAY_S);
|
||||
XUngrabServer(DisplayHandle);
|
||||
XFlush(DisplayHandle);
|
||||
|
||||
|
||||
if (SystrayMgrWindow != IntPtr.Zero)
|
||||
{
|
||||
//XSelectInput(DisplayHandle, SystrayMgrWindow, (IntPtr)XEventMask.StructureNotifyMask);
|
||||
|
||||
XSizeHints size_hints;
|
||||
|
||||
// We are going to be directly mapped by the system tray, so mark as mapped
|
||||
// so we can later properly unmap it.
|
||||
//XWindowAttributes attributes = new XWindowAttributes();
|
||||
//XGetWindowAttributes(x11info.Display, XDefaultRootWindow(x11info.Display), ref attributes);
|
||||
//Console.WriteLine(attributes.width + "," + attributes.height);
|
||||
|
||||
size_hints = new XSizeHints();
|
||||
|
||||
size_hints.flags = (IntPtr)(XSizeHintsFlags.PMinSize | XSizeHintsFlags.PMaxSize | XSizeHintsFlags.PBaseSize);
|
||||
|
||||
size_hints.min_width = 16;
|
||||
size_hints.min_height = 16;
|
||||
size_hints.max_width = 16;
|
||||
size_hints.max_height = 16;
|
||||
size_hints.base_width = 16;
|
||||
size_hints.base_height = 16;
|
||||
|
||||
XSetWMNormalHints(DisplayHandle, Handle, ref size_hints);
|
||||
|
||||
IntPtr[] atoms = new IntPtr[2];
|
||||
atoms[0] = (IntPtr)1; // Version 1
|
||||
atoms[1] = (IntPtr)1; // we want to be mapped
|
||||
|
||||
XChangeProperty(DisplayHandle, Handle, LinuxPlatform.Platform.Info.Atoms._XEMBED_INFO, LinuxPlatform.Platform.Info.Atoms._XEMBED_INFO, 32, PropertyMode.Replace, atoms, 2);
|
||||
|
||||
SendNetClientMessage(SystrayMgrWindow, LinuxPlatform.Platform.Info.Atoms._NET_SYSTEM_TRAY_OPCODE, IntPtr.Zero, (IntPtr)SystrayRequest.SYSTEM_TRAY_REQUEST_DOCK, Handle);
|
||||
//XReparentWindow(DisplayHandle, Handle, SystrayMgrWindow, 0, 0);
|
||||
Invalidate();
|
||||
if (maped)
|
||||
{
|
||||
XMapWindow(x11info.Display, Handle);
|
||||
}
|
||||
maped = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XUnmapWindow(DisplayHandle, Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendNetClientMessage(IntPtr window, IntPtr message_type, IntPtr l0, IntPtr l1, IntPtr l2)
|
||||
{
|
||||
XEvent xev;
|
||||
|
||||
xev = new XEvent();
|
||||
xev.ClientMessageEvent.type = XEventName.ClientMessage;
|
||||
xev.ClientMessageEvent.send_event = true;
|
||||
xev.ClientMessageEvent.window = window;
|
||||
xev.ClientMessageEvent.message_type = message_type;
|
||||
xev.ClientMessageEvent.format = 32;
|
||||
xev.ClientMessageEvent.ptr1 = l0;
|
||||
xev.ClientMessageEvent.ptr2 = l1;
|
||||
xev.ClientMessageEvent.ptr3 = l2;
|
||||
XSendEvent(DisplayHandle, window, false, new IntPtr((int)EventMask.NoEventMask), ref xev);
|
||||
//XSync(DisplayHandle, false);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (bitmap != null)
|
||||
{
|
||||
bitmap.Dispose();
|
||||
bitmap = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user