iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
Software Development

用python做一個X11 WM系列 第 10

Day 10|用滑鼠右鍵調整視窗大小

  • 分享至 

  • xImage
  •  

調大小的原理跟移動差不多,視窗原本的大小加上滑鼠移動的距離,下面註解我都有寫到(那些註解是我寫的,不要以為很詳細就是AI。 XD)

from Xlib import display,X,XK,xobject,Xcursorfont
dpy=display.Display()
screen=dpy.screen()
root=screen.root
#註冊事件
screen.root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("q")),X.Mod4Mask,1,X.GrabModeAsync, X.GrabModeAsync)
screen.root.grab_key(dpy.keysym_to_keycode(XK.string_to_keysym("r")),X.Mod4Mask,1,X.GrabModeAsync, X.GrabModeAsync)
screen.root.grab_button(X.Button1,X.Mod4Mask,True,X.ButtonPressMask| X.ButtonReleaseMask| X.PointerMotionMask,X.GrabModeAsync,X.GrabModeAsync,X.NONE,X.NONE,)
screen.root.grab_button(X.Button3,X.Mod4Mask,True,X.ButtonPressMask| X.ButtonReleaseMask| X.PointerMotionMask,X.GrabModeAsync,X.GrabModeAsync,X.NONE,X.NONE,)
font = dpy.open_font('cursor')           # 開啟 cursor 字型
cursor = font.create_glyph_cursor(
    font,                                # mask 用同一個 font
    Xcursorfont.gumby,                   # 游標形狀(source_char)https://xorg.freedesktop.org/archive/current/doc/libX11/libX11/libX11.html#x_font_cursors
    #Xcursorfont.left_ptr,
    Xcursorfont.gumby+1,                 # mask_char(通常是 +1)
    (0, 0, 0),                           # 前景色 RGB(黑色)
    (65535, 65535, 65535)                # 背景色 RGB(白色)
)

root.change_attributes(cursor=cursor)
q_code=dpy.keysym_to_keycode(XK.string_to_keysym("q"))
r_code=dpy.keysym_to_keycode(XK.string_to_keysym("r"))

status=None
while True:
    event=dpy.next_event()
    """
    root.set_input_focus(X.RevertToParent,X.CurrentTime)
    if event.child!=X.NONE:
        print(dpy.get_input_focus())
    """
    if event.type==X.ButtonPress and event.child!=X.NONE:
        status=event
        #滑鼠原本的xy
        mc_origin_x=event.root_x
        mc_origin_y=event.root_y
        
        if status.detail==X.Button1:
            #視窗原本的xy
            win_origin_x=event.child.get_geometry().x
            win_origin_y=event.child.get_geometry().y
        elif status.detail==X.Button3:
            #視窗原本的寬高
            win_origin_width=event.child.get_geometry().width
            win_origin_height=event.child.get_geometry().height
    elif event.type==X.MotionNotify and status!=None:
        #滑鼠移動後的xy
        moved_x=event.root_x
        moved_y=event.root_y
        
        #滑鼠了xy移動多少
        move_x=moved_x-mc_origin_x
        move_y=moved_y-mc_origin_y
        if status.detail==X.Button1:
            status.child.configure(x=win_origin_x+move_x,#視窗原本的位置+滑鼠移動了多少(也就是要移動多少)
                                   y=win_origin_y+move_y)
        elif status.detail==X.Button3:
            #最小視窗寬高常數(最小為1),根據PEP8規定常數名為全大寫,用底線分隔
            MIN_WIN_WIDTH=50
            MIN_WIN_HEIGHT=50
            
            status.child.configure(width=max(win_origin_width+move_x,MIN_WIN_WIDTH),#視窗原本的大小+滑鼠移動了多少,max()避免視窗大小小於最小視窗寬高常數
                                   height=max(win_origin_height+move_y,MIN_WIN_HEIGHT))
        dpy.flush()
    elif event.type==X.ButtonRelease:
        status=None
    elif event.type==X.KeyPress and event.child!= X.NONE:
        if event.detail==q_code:
            print(f"kill client:{event.child.get_wm_name()}")
            event.child.kill_client()
            #event.child是滑鼠底下的視窗
        '''
        elif event.detail==r_code:
            print(f"moving window:{event.child.get_wm_name()}")
            
            event.child.configure(x=100,y=100,width=200,height=300,border_width=100)
            #configure(x,y,width,height)
        '''
        dpy.flush()
#記得關num lock

我註解有特別寫到max()避免視窗大小小於最小視窗寬高常數是因為沒有限制最小寬高就可以把視窗大小調成0或負數,這樣會報錯

Traceback (most recent call last):
  File "/home/zixgggg/i4/main.py", line 65, in <module>
    status.child.configure(width=win_origin_width+move_x,#視窗原本的大小+滑鼠移動了多少,max()避免視窗大小小於最小視窗寬高常數
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                           height=win_origin_height+move_y)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zixgggg/i4/.venv/lib/python3.13/site-packages/Xlib/xobject/drawable.py", line 408, in configure
    request.ConfigureWindow(display = self.display,
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
                            onerror = onerror,
                            ^^^^^^^^^^^^^^^^^^
                            window = self.id,
                            ^^^^^^^^^^^^^^^^^
                            attrs = keys)
                            ^^^^^^^^^^^^^
  File "/home/zixgggg/i4/.venv/lib/python3.13/site-packages/Xlib/protocol/rq.py", line 1346, in __init__
    self._binary = self._request.to_binary(*args, **keys)
                   ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/home/zixgggg/i4/.venv/lib/python3.13/site-packages/Xlib/protocol/rq.py", line 1018, in to_binary
    v, l, fm = f.pack_value(field_args[f.name], keys)
               ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zixgggg/i4/.venv/lib/python3.13/site-packages/Xlib/protocol/rq.py", line 756, in pack_value
    d = struct.pack('=' + field.structcode, val)
struct.error: 'H' format requires 0 <= number <= 65535

抱歉前幾天文章都比較水,放學後還要做特選備審資料有點累就懶得弄鐵人賽專案,雖然說我的文章沒什麼人看但我還是要寫好文章並堅持完賽,順帶一提我agy的token用完了所以昨天跟今天就試試看codex,這兩天的東西都是他教我的,我對AI不太瞭解但是我覺得codex用的chatgpt比較聰明(雖然agy也可以選模型),而且codex不知道是token比較多還是他用的比較少,這兩天用還剩72%,也有可能是我用比較少的錯覺


上一篇
Day 9|試著用滑鼠移動視窗
下一篇
Day 11|今天比較懶
系列文
用python做一個X11 WM14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言