Trời tính không bằng máy tính

blog, khám phá

Từ dòng code tới màn hình (phần 1)

Từ dòng code tới màn hình

Đã bao giờ bạn tự hỏi, vì sao khi mở một app trên máy tính, thì app đó lại hiện trong cửa sổ của nó? Thứ gì giúp điều khiển cửa sổ phòng to, thu nhỏ, cửa sổ nọ có thể đè lên trên cửa sổ khác? Vì sao nút thoát [x] ở trên windows và mac lại trông khác nhau? Vì sao khi windows XP bị lag, cửa sổ kéo dài thành những vệt nhìn trông rất… “hoài cổ”?

Loạt bài viết mang tên “Từ dòng code tới màn hình” này sẽ đánh dấu sự trở lại của mình sau một khoảng thời gian dài vắng bóng.

Vậy vì sao lại đi được từ dòng code tới màn hình? Hãy cùng mình khám phá ở loạt bài viết này nhé!

Ngày xửa ngày xưa…

Từ cách đây rất lâu, thời tổ tiên của máy vi tính hiện đại, các máy tính chưa có vi xử lý đồ họa (GPU) và chỉ có thể hiển thị được chữ.

Hình ảnh dưới đây là một màn hình máy tính như thế. Đúng ra nó là một cái “terminal”:

Vậy terminal và màn hình khác nhau chỗ nào? Nói tóm gọn, terminal nhận vào tín hiệu là text (chứ không phải tín hiệu hình ảnh dưới dạng pixel như màn hình). Ví dụ nếu bạn muốn hiện chữ “HELLO” lên màn hình, bạn cần truyền vào terminal đoạn dữ liệu nhị phân “01001000 – 01000101 – 01001100 – 01001100 – 01001111” tương ứng với 5 chữ cái H – E – L – L – O. Việc hiện ở đâu trên màn hình, hay font chữ ra sao, là do terminal quyết định.

Nói đến đây, chắc hẳn bạn cũng đủ nhận ra đây là “tổ tiên” của telnel? Chính xác là vậy, telnet và về sau là ssh hoạt động chủ yếu dựa theo nguyên lý này: thay vì truyền tín hiệu hình ảnh, chỉ cần chữ là đủ.

Nhưng chỉ chữ thôi thì hơi hạn chế nhỉ, nhỡ đâu mình muốn chia đôi màn hình để hiển thị 2 cột? Và đây, thứ gọi là “window manager” ra đời:

Ý tưởng của “window manager” thuở sơ khai này, đó là sử dụng những ký tự ASCII đặc biệt để “vẽ” các đường nét góc cạnh của cửa sổ. Lưu ý nhỏ, bạn tránh nhầm lẫn khái niệm này với tên của hệ điều hành “Windows” nhé! Hãy nghĩ “window manager” giống như “một phần mềm giúp quản lý việc hiển thị”

Hiểu một cách nôm na, “window manager” tạo ra 2 (hoặc nhiều) terminal ảo, và mỗi phần mềm có thể “gửi” dữ liệu text vào 1 terminal. Phần mềm “window manager” sau đó sẽ phụ trách việc “gộp” nhiều luồng dữ liệu này, đặt nó vào vị trí chính xác trên màn hình, và sau đó vẽ các đường nét bao viền bên ngoài.

Ảnh dưới đây là bảng các ký tự đặc biệt để vẽ phần viền ngoài của cửa sổ trên một terminal:

Có thêm đồ họa

Bây giờ là năm 1985, bạn có trong tay một bản copy của Windows 1.0, bạn thật hồi hộp đút đĩa mềm vào ổ đĩa… và nó kêu… cạch… cạch… xèèèèèè… rồi màn hình hiện ra:

Thật thú vị khi màn hình không chỉ còn nền đen và chữ xanh nữa. Bây giờ, mọi phần mềm hiển thị đều là những pixel sống động, thậm chí cửa sổ nọ có thể chồng lên trên cửa sổ kia.

Chuyện gì đã xảy ra?

Hãy cùng nhìn vào file code của một phần mềm đơn giản trên Windows 1.0. Xin giới thiệu, phần mềm mang tên HELLO.C: https://github.com/NCommander/win1-hello-world-annotations/blob/master/HELLO.C

Đoạn code sau đây sẽ được gọi mỗi khi màn hình cập nhật (hiểu nôm na như kiểu mỗi frame trong số 30 hay 60 fps):

void HelloPaint( hDC )
HDC hDC;
{
    TextOut( hDC,
             (short)10,
             (short)10,
             (LPSTR)szMessage,
             (short)MessageLength );
}

Đoạn code này chỉ đơn giản là hiện chữ “Hello Windows!” ra ngoài màn hình. Nhưng chỉ có một dòng chữ hiện ra thôi mà, vì sao phải gọi đi gọi lại liên tục làm gì?

Vậy giờ, hãy tưởng tượng theo kiểu một “họa sĩ”. Nếu bạn muốn vẽ 2 hình khối, một hình màu đỏ và một hình màu xanh biển chồng lên nhau. Đầu tiên, bạn sẽ phải vẽ hình đỏ trước, sau đó mới vẽ hình xanh biển:

Vậy giờ nếu mình đảo vị trí: màu xanh biển lên trước màu đỏ. Cách đơn giản nhất là chúng ta xóa hết đi, rồi vẽ hình màu xanh biển trước, rồi mới vẽ màu đỏ:

Tương tự như vậy, thực chất, việc các cửa sổ có thể chồng lên nhau được, chẳng qua là do window manager chọn “vẽ” cái nào trước, cái nào sau. Ở các phiên bản sơ khai, phần mềm sẽ chịu trách nhiệm “vẽ” nội dung cửa sổ của mình trực tiếp lên trên màn hình, và thực chất window manager chỉ điều khiển “cái nào trước, cái nào sau”

Các phiên bản window manager về sau phức tạp hơn, ví dụ như ở cách phiên bản hiện đại, thay vì để ứng dụng “vẽ” trực tiếp lên màn hình, thì nó sẽ cho ứng dụng “vẽ” tạm lên một màn hình ảo, rồi window manager mới gộp (hay còn gọi là compositor) lại để thành “hình ảnh” cuối hiện ra màn hình thật.

Các ví dụ trong bài mình lấy từ hệ điều hành Windows, nhưng thực chất ý tưởng này xuất hiện trên mọi loại hệ điều hành. Ví dụ ở macOS, việc này được thực hiện bởi “Quartz Compositor”

Ở Linux, người ta từng dùng X11 / Xorg và hiện tại là Wayland

Ở Android, người ta dùng WindowManager, là một component được tích hợp sẵn trong framework của Android.

Bài viết này đã kha khá thông tin, mình sẽ tạm dừng ở đây. Ở bài viết sau, chúng ta sẽ tìm hiểu làm thế nào bên trong một phần mềm, nó có thể “vẽ” ra một hàng chữ, một nút bấm,… cũng như sự khác biệt giữa native UI, web based, react native, flutter,…

Bonus

Vậy cuối cùng thì vì sao khi Windows XP bị lag, thì cửa sổ để lại những vệt dài?

Lý do là vì ở Windows XP đổ lại, nó có giới hạn thời gian mà một phần mềm được “vẽ” nội dung của nó ra màn hình. Nếu quá thời gian này mà cửa sổ chưa vẽ xong, thì mặc định là Windows XP sẽ tái sử dụng lại hình ảnh trước đó.

Vì sự “tái sử dụng” này, mỗi lần cửa sổ ở phía trên cửa sổ bị lag di chuyển, nó sẽ lại “tự vẽ” một hình ảnh mới của nó lên hình ảnh đã có sẵn:

Nguồn

* Bài viết này được mình sự biên soạn và tự viết, không có đoạn nào dùng google translate. Hình ảnh hoặc là lấy trên mạng, hoặc là mình tự ngồi photoshop; Không có ảnh nào do AI tạo ra.

MỚI! Đăng ký nhận bài viết mới nhất qua chatbot: