XReparentWindow踩坑分析

        X11是Linux发行系统中广泛采用的显示协议,各个系统基本上都支持XLib库,作为底层接口,XReparentWindow接口的功能就是重新设置父窗口,注意这个可以跨进程设置父窗口,例如将已经运行的进程的父窗口设置自己的程序Wid,即可将第三方进程嵌入到自己的程序窗口中,自己用这个接口写了一段代码,在UOS上运行的正常,后面跑在Kylin 4.0.2和V10上,程序出现了一些难以琢磨的情况,嵌入的程序无法focus,查阅到qt的container容器可以完成这个功能,查阅了qt4和qt5的源码,发先程序嵌入确实不是简简单单的XReparentWindow调用,后续还涉及到各种消息转发操作,后续学习。

bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
{
    Q_D(QX11EmbedContainer);
    switch (event->type()) {
    case QEvent::KeyPress:
        // Forward any keypresses to our client.
	if (o == this && d->client) {
	    lastKeyEvent.window = d->client;
	    XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
	    return true;
	}
	break;
    case QEvent::KeyRelease:
	// Forward any keyreleases to our client.
	if (o == this && d->client) {
	    lastKeyEvent.window = d->client;
	    XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
	    return true;
	}
	break;

    case QEvent::WindowActivate:
	// When our container window is activated, we pass the
	// activation message on to our client. Note that X input
	// focus is set to our focus proxy. We want to intercept all
	// keypresses.
	if (o == window() && d->client) {
            if (d->clientIsXEmbed) {
                sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
            } else {
                d->checkGrab();
                if (hasFocus())
                    XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
            }
            if (!d->isEmbedded())
                d->moveInputToProxy();
	}
	break;
    case QEvent::WindowDeactivate:
	// When our container window is deactivated, we pass the
	// deactivation message to our client.
	if (o == window() && d->client) {
	    if (d->clientIsXEmbed)
		sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
	    else
		d->checkGrab();
	}
	break;
    case QEvent::FocusIn:
        // When receiving FocusIn events generated by Tab or Backtab,
	// we pass focus on to our client. Any mouse activity is sent
	// directly to the client, and it will ask us for focus with
	// XEMBED_REQUEST_FOCUS.
	if (o == this && d->client) {
            if (!d->isEmbedded())
                d->activeContainer = this;

            if (d->clientIsXEmbed) {
                if (!d->isEmbedded())
                    d->moveInputToProxy();

		QFocusEvent *fe = (QFocusEvent *)event;
		switch (fe->reason()) {
		case Qt::TabFocusReason:
		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
		    break;
		case Qt::BacktabFocusReason:
		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
		    break;
		default:
		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
		    break;
		}
	    } else {
		d->checkGrab();
                XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
	    }
	}

	break;
    case QEvent::FocusOut: {
	// When receiving a FocusOut, we ask our client to remove its
	// focus.
	if (o == this && d->client) {
            if (!d->isEmbedded()) {
                d->activeContainer = 0;
                if (isActiveWindow())
                    d->moveInputToProxy();
            }

	    if (d->clientIsXEmbed) {
		QFocusEvent *fe = (QFocusEvent *)event;
		if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
	    } else {
		d->checkGrab();
	    }
	}
    }
	break;

    case QEvent::Close: {
	if (o == this && d->client) {
	    // Unmap the client and reparent it to the root window.
	    // Wait until the messages have been processed. Then ask
	    // the window manager to delete the window.
	    XUnmapWindow(x11Info().display(), d->client);
	    XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(x11Info().screen()), 0, 0);
	    XSync(x11Info().display(), false);

	    XEvent ev;
	    memset(&ev, 0, sizeof(ev));
	    ev.xclient.type = ClientMessage;
	    ev.xclient.window = d->client;
	    ev.xclient.message_type = ATOM(WM_PROTOCOLS);
	    ev.xclient.format = 32;
	    ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
	    XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);

	    XFlush(x11Info().display());
	    d->client = 0;
	    d->clientIsXEmbed = false;
            d->wmMinimumSizeHint = QSize();
            updateGeometry();
            setEnabled(false);
	    update();

	    emit clientClosed();
	}
    }
    default:
	break;
    }

    return QWidget::eventFilter(o, event);
}

        麒麟系统和WPS软件,qt4的QXEmbedContainer和qt5 createContainer嵌入wps时显示空白,慢慢研究解决方案去。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值