You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使SDL窗口不可移动?C语言SDL2+OpenGL游戏开发疑问

嘿,我之前做SDL2项目的时候也碰到过这个问题——SDL2确实没提供直接让窗口不可移动的内置标志位,但我们可以绕个弯,调用对应平台的原生API来实现,毕竟SDL底层也是靠系统窗口管理器干活的。下面分Windows和Linux两个最常用的平台给你说具体怎么做:

Windows平台实现方案

首先得引入Windows的头文件,注意要放在SDL头文件前面,避免编译冲突:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>

创建好SDL窗口之后,我们需要拿到它的原生Windows窗口句柄,然后通过修改窗口过程来拦截拖动操作:

// 全局变量保存原窗口过程
WNDPROC g_oldWindowProc = NULL;

// 自定义窗口过程,拦截拖动相关消息
LRESULT CALLBACK CustomWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    // 当系统检测到鼠标点击标题栏时,我们把它伪装成点击窗口内容区域
    if (uMsg == WM_NCHITTEST) {
        LRESULT hitResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
        if (hitResult == HTCAPTION) {
            return HTCLIENT;
        }
        return hitResult;
    }
    // 其他消息交给原窗口处理
    return CallWindowProc(g_oldWindowProc, hwnd, uMsg, wParam, lParam);
}

int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);

    // 创建你的OpenGL窗口(参数换成你自己的)
    SDL_Window* window = SDL_CreateWindow(
        "固定位置的游戏窗口",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        800, 600,
        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
    );

    // 获取Windows窗口的原生句柄
    SDL_SysWMinfo wmInfo;
    SDL_VERSION(&wmInfo.version);
    if (SDL_GetWindowWMInfo(window, &wmInfo)) {
        HWND hwnd = wmInfo.info.win.window;
        // 替换窗口过程为我们自定义的
        g_oldWindowProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)CustomWindowProc);

        // 额外:可以去掉窗口的最大化和可缩放按钮,让窗口看起来更“固定”
        LONG windowStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
        windowStyle &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
        SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
        // 刷新窗口样式
        SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
    }

    // 这里放你的OpenGL初始化和游戏循环代码...

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

原理很简单:通过拦截WM_NCHITTEST消息,把用户点击标题栏的操作伪装成点击窗口内容区域,这样系统就不会触发窗口拖动的逻辑了。

Linux(X11)平台实现方案

Linux下我们用X11的API来告诉窗口管理器“这个窗口位置是固定的,别让用户拖动”:

#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <X11/Xlib.h>

int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window* window = SDL_CreateWindow(
        "固定位置的游戏窗口",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        800, 600,
        SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
    );

    // 获取X11窗口的原生信息
    SDL_SysWMinfo wmInfo;
    SDL_VERSION(&wmInfo.version);
    if (SDL_GetWindowWMInfo(window, &wmInfo)) {
        Display* display = wmInfo.info.x11.display;
        Window x11Window = wmInfo.info.x11.window;

        // 申请并设置窗口大小提示,标记位置为程序固定
        XSizeHints* sizeHints = XAllocSizeHints();
        if (sizeHints != NULL) {
            XGetWMNormalHints(display, x11Window, sizeHints, NULL);
            // 开启PPosition标志,通知窗口管理器位置不可改
            sizeHints->flags |= PPosition;
            XSetWMNormalHints(display, x11Window, sizeHints);
            XFree(sizeHints);
        }
    }

    // 这里放你的OpenGL初始化和游戏循环代码...

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

这个方法是通过X11的XSizeHints设置PPosition标志,主流窗口管理器(GNOME、KDE、XFCE等)都会遵守这个设置,禁止用户拖动窗口。

编译注意事项

  • Windows平台编译时,需要链接user32.lib(一般IDE会自动处理,手动编译的话加-luser32)。
  • Linux平台编译时,要链接X11库,编译命令里加-lX11。

内容的提问来源于stack exchange,提问作者Zacarias Fifa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:28:26