console.c 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404
  1. /*
  2. * QEMU graphical console
  3. *
  4. * Copyright (c) 2004 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "ui/console.h"
  26. #include "hw/qdev-core.h"
  27. #include "qapi/error.h"
  28. #include "qapi/qapi-commands-ui.h"
  29. #include "qemu/module.h"
  30. #include "qemu/option.h"
  31. #include "qemu/timer.h"
  32. #include "chardev/char-fe.h"
  33. #include "trace.h"
  34. #include "exec/memory.h"
  35. #define DEFAULT_BACKSCROLL 512
  36. #define CONSOLE_CURSOR_PERIOD 500
  37. typedef struct TextAttributes {
  38. uint8_t fgcol:4;
  39. uint8_t bgcol:4;
  40. uint8_t bold:1;
  41. uint8_t uline:1;
  42. uint8_t blink:1;
  43. uint8_t invers:1;
  44. uint8_t unvisible:1;
  45. } TextAttributes;
  46. typedef struct TextCell {
  47. uint8_t ch;
  48. TextAttributes t_attrib;
  49. } TextCell;
  50. #define MAX_ESC_PARAMS 3
  51. enum TTYState {
  52. TTY_STATE_NORM,
  53. TTY_STATE_ESC,
  54. TTY_STATE_CSI,
  55. };
  56. typedef struct QEMUFIFO {
  57. uint8_t *buf;
  58. int buf_size;
  59. int count, wptr, rptr;
  60. } QEMUFIFO;
  61. static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
  62. {
  63. int l, len;
  64. l = f->buf_size - f->count;
  65. if (len1 > l)
  66. len1 = l;
  67. len = len1;
  68. while (len > 0) {
  69. l = f->buf_size - f->wptr;
  70. if (l > len)
  71. l = len;
  72. memcpy(f->buf + f->wptr, buf, l);
  73. f->wptr += l;
  74. if (f->wptr >= f->buf_size)
  75. f->wptr = 0;
  76. buf += l;
  77. len -= l;
  78. }
  79. f->count += len1;
  80. return len1;
  81. }
  82. static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
  83. {
  84. int l, len;
  85. if (len1 > f->count)
  86. len1 = f->count;
  87. len = len1;
  88. while (len > 0) {
  89. l = f->buf_size - f->rptr;
  90. if (l > len)
  91. l = len;
  92. memcpy(buf, f->buf + f->rptr, l);
  93. f->rptr += l;
  94. if (f->rptr >= f->buf_size)
  95. f->rptr = 0;
  96. buf += l;
  97. len -= l;
  98. }
  99. f->count -= len1;
  100. return len1;
  101. }
  102. typedef enum {
  103. GRAPHIC_CONSOLE,
  104. TEXT_CONSOLE,
  105. TEXT_CONSOLE_FIXED_SIZE
  106. } console_type_t;
  107. struct QemuConsole {
  108. Object parent;
  109. int index;
  110. console_type_t console_type;
  111. DisplayState *ds;
  112. DisplaySurface *surface;
  113. int dcls;
  114. DisplayChangeListener *gl;
  115. bool gl_block;
  116. int window_id;
  117. /* Graphic console state. */
  118. Object *device;
  119. uint32_t head;
  120. QemuUIInfo ui_info;
  121. QEMUTimer *ui_timer;
  122. const GraphicHwOps *hw_ops;
  123. void *hw;
  124. /* Text console state */
  125. int width;
  126. int height;
  127. int total_height;
  128. int backscroll_height;
  129. int x, y;
  130. int x_saved, y_saved;
  131. int y_displayed;
  132. int y_base;
  133. TextAttributes t_attrib_default; /* default text attributes */
  134. TextAttributes t_attrib; /* currently active text attributes */
  135. TextCell *cells;
  136. int text_x[2], text_y[2], cursor_invalidate;
  137. int echo;
  138. int update_x0;
  139. int update_y0;
  140. int update_x1;
  141. int update_y1;
  142. enum TTYState state;
  143. int esc_params[MAX_ESC_PARAMS];
  144. int nb_esc_params;
  145. Chardev *chr;
  146. /* fifo for key pressed */
  147. QEMUFIFO out_fifo;
  148. uint8_t out_fifo_buf[16];
  149. QEMUTimer *kbd_timer;
  150. QTAILQ_ENTRY(QemuConsole) next;
  151. };
  152. struct DisplayState {
  153. QEMUTimer *gui_timer;
  154. uint64_t last_update;
  155. uint64_t update_interval;
  156. bool refreshing;
  157. bool have_gfx;
  158. bool have_text;
  159. QLIST_HEAD(, DisplayChangeListener) listeners;
  160. };
  161. static DisplayState *display_state;
  162. static QemuConsole *active_console;
  163. static QTAILQ_HEAD(, QemuConsole) consoles =
  164. QTAILQ_HEAD_INITIALIZER(consoles);
  165. static bool cursor_visible_phase;
  166. static QEMUTimer *cursor_timer;
  167. static void text_console_do_init(Chardev *chr, DisplayState *ds);
  168. static void dpy_refresh(DisplayState *s);
  169. static DisplayState *get_alloc_displaystate(void);
  170. static void text_console_update_cursor_timer(void);
  171. static void text_console_update_cursor(void *opaque);
  172. static void gui_update(void *opaque)
  173. {
  174. uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
  175. uint64_t dcl_interval;
  176. DisplayState *ds = opaque;
  177. DisplayChangeListener *dcl;
  178. QemuConsole *con;
  179. ds->refreshing = true;
  180. dpy_refresh(ds);
  181. ds->refreshing = false;
  182. QLIST_FOREACH(dcl, &ds->listeners, next) {
  183. dcl_interval = dcl->update_interval ?
  184. dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
  185. if (interval > dcl_interval) {
  186. interval = dcl_interval;
  187. }
  188. }
  189. if (ds->update_interval != interval) {
  190. ds->update_interval = interval;
  191. QTAILQ_FOREACH(con, &consoles, next) {
  192. if (con->hw_ops->update_interval) {
  193. con->hw_ops->update_interval(con->hw, interval);
  194. }
  195. }
  196. trace_console_refresh(interval);
  197. }
  198. ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
  199. timer_mod(ds->gui_timer, ds->last_update + interval);
  200. }
  201. static void gui_setup_refresh(DisplayState *ds)
  202. {
  203. DisplayChangeListener *dcl;
  204. bool need_timer = false;
  205. bool have_gfx = false;
  206. bool have_text = false;
  207. QLIST_FOREACH(dcl, &ds->listeners, next) {
  208. if (dcl->ops->dpy_refresh != NULL) {
  209. need_timer = true;
  210. }
  211. if (dcl->ops->dpy_gfx_update != NULL) {
  212. have_gfx = true;
  213. }
  214. if (dcl->ops->dpy_text_update != NULL) {
  215. have_text = true;
  216. }
  217. }
  218. if (need_timer && ds->gui_timer == NULL) {
  219. ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
  220. timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
  221. }
  222. if (!need_timer && ds->gui_timer != NULL) {
  223. timer_del(ds->gui_timer);
  224. timer_free(ds->gui_timer);
  225. ds->gui_timer = NULL;
  226. }
  227. ds->have_gfx = have_gfx;
  228. ds->have_text = have_text;
  229. }
  230. void graphic_hw_update(QemuConsole *con)
  231. {
  232. if (!con) {
  233. con = active_console;
  234. }
  235. if (con && con->hw_ops->gfx_update) {
  236. con->hw_ops->gfx_update(con->hw);
  237. }
  238. }
  239. void graphic_hw_gl_block(QemuConsole *con, bool block)
  240. {
  241. assert(con != NULL);
  242. con->gl_block = block;
  243. if (con->hw_ops->gl_block) {
  244. con->hw_ops->gl_block(con->hw, block);
  245. }
  246. }
  247. int qemu_console_get_window_id(QemuConsole *con)
  248. {
  249. return con->window_id;
  250. }
  251. void qemu_console_set_window_id(QemuConsole *con, int window_id)
  252. {
  253. con->window_id = window_id;
  254. }
  255. void graphic_hw_invalidate(QemuConsole *con)
  256. {
  257. if (!con) {
  258. con = active_console;
  259. }
  260. if (con && con->hw_ops->invalidate) {
  261. con->hw_ops->invalidate(con->hw);
  262. }
  263. }
  264. static void ppm_save(const char *filename, DisplaySurface *ds,
  265. Error **errp)
  266. {
  267. int width = pixman_image_get_width(ds->image);
  268. int height = pixman_image_get_height(ds->image);
  269. int fd;
  270. FILE *f;
  271. int y;
  272. int ret;
  273. pixman_image_t *linebuf;
  274. trace_ppm_save(filename, ds);
  275. fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
  276. if (fd == -1) {
  277. error_setg(errp, "failed to open file '%s': %s", filename,
  278. strerror(errno));
  279. return;
  280. }
  281. f = fdopen(fd, "wb");
  282. ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
  283. if (ret < 0) {
  284. linebuf = NULL;
  285. goto write_err;
  286. }
  287. linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
  288. for (y = 0; y < height; y++) {
  289. qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
  290. clearerr(f);
  291. ret = fwrite(pixman_image_get_data(linebuf), 1,
  292. pixman_image_get_stride(linebuf), f);
  293. (void)ret;
  294. if (ferror(f)) {
  295. goto write_err;
  296. }
  297. }
  298. out:
  299. qemu_pixman_image_unref(linebuf);
  300. fclose(f);
  301. return;
  302. write_err:
  303. error_setg(errp, "failed to write to file '%s': %s", filename,
  304. strerror(errno));
  305. unlink(filename);
  306. goto out;
  307. }
  308. void qmp_screendump(const char *filename, bool has_device, const char *device,
  309. bool has_head, int64_t head, Error **errp)
  310. {
  311. QemuConsole *con;
  312. DisplaySurface *surface;
  313. if (has_device) {
  314. con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
  315. errp);
  316. if (!con) {
  317. return;
  318. }
  319. } else {
  320. if (has_head) {
  321. error_setg(errp, "'head' must be specified together with 'device'");
  322. return;
  323. }
  324. con = qemu_console_lookup_by_index(0);
  325. if (!con) {
  326. error_setg(errp, "There is no console to take a screendump from");
  327. return;
  328. }
  329. }
  330. graphic_hw_update(con);
  331. surface = qemu_console_surface(con);
  332. if (!surface) {
  333. error_setg(errp, "no surface");
  334. return;
  335. }
  336. ppm_save(filename, surface, errp);
  337. }
  338. void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
  339. {
  340. if (!con) {
  341. con = active_console;
  342. }
  343. if (con && con->hw_ops->text_update) {
  344. con->hw_ops->text_update(con->hw, chardata);
  345. }
  346. }
  347. static void vga_fill_rect(QemuConsole *con,
  348. int posx, int posy, int width, int height,
  349. pixman_color_t color)
  350. {
  351. DisplaySurface *surface = qemu_console_surface(con);
  352. pixman_rectangle16_t rect = {
  353. .x = posx, .y = posy, .width = width, .height = height
  354. };
  355. pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
  356. &color, 1, &rect);
  357. }
  358. /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
  359. static void vga_bitblt(QemuConsole *con,
  360. int xs, int ys, int xd, int yd, int w, int h)
  361. {
  362. DisplaySurface *surface = qemu_console_surface(con);
  363. pixman_image_composite(PIXMAN_OP_SRC,
  364. surface->image, NULL, surface->image,
  365. xs, ys, 0, 0, xd, yd, w, h);
  366. }
  367. /***********************************************************/
  368. /* basic char display */
  369. #define FONT_HEIGHT 16
  370. #define FONT_WIDTH 8
  371. #include "vgafont.h"
  372. #define QEMU_RGB(r, g, b) \
  373. { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
  374. static const pixman_color_t color_table_rgb[2][8] = {
  375. { /* dark */
  376. [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
  377. [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
  378. [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xaa, 0x00), /* green */
  379. [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
  380. [QEMU_COLOR_RED] = QEMU_RGB(0xaa, 0x00, 0x00), /* red */
  381. [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
  382. [QEMU_COLOR_YELLOW] = QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
  383. [QEMU_COLOR_WHITE] = QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
  384. },
  385. { /* bright */
  386. [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
  387. [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xff), /* blue */
  388. [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xff, 0x00), /* green */
  389. [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
  390. [QEMU_COLOR_RED] = QEMU_RGB(0xff, 0x00, 0x00), /* red */
  391. [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
  392. [QEMU_COLOR_YELLOW] = QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
  393. [QEMU_COLOR_WHITE] = QEMU_RGB(0xff, 0xff, 0xff), /* white */
  394. }
  395. };
  396. static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
  397. TextAttributes *t_attrib)
  398. {
  399. static pixman_image_t *glyphs[256];
  400. DisplaySurface *surface = qemu_console_surface(s);
  401. pixman_color_t fgcol, bgcol;
  402. if (t_attrib->invers) {
  403. bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
  404. fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
  405. } else {
  406. fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
  407. bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
  408. }
  409. if (!glyphs[ch]) {
  410. glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
  411. }
  412. qemu_pixman_glyph_render(glyphs[ch], surface->image,
  413. &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
  414. }
  415. static void text_console_resize(QemuConsole *s)
  416. {
  417. TextCell *cells, *c, *c1;
  418. int w1, x, y, last_width;
  419. last_width = s->width;
  420. s->width = surface_width(s->surface) / FONT_WIDTH;
  421. s->height = surface_height(s->surface) / FONT_HEIGHT;
  422. w1 = last_width;
  423. if (s->width < w1)
  424. w1 = s->width;
  425. cells = g_new(TextCell, s->width * s->total_height + 1);
  426. for(y = 0; y < s->total_height; y++) {
  427. c = &cells[y * s->width];
  428. if (w1 > 0) {
  429. c1 = &s->cells[y * last_width];
  430. for(x = 0; x < w1; x++) {
  431. *c++ = *c1++;
  432. }
  433. }
  434. for(x = w1; x < s->width; x++) {
  435. c->ch = ' ';
  436. c->t_attrib = s->t_attrib_default;
  437. c++;
  438. }
  439. }
  440. g_free(s->cells);
  441. s->cells = cells;
  442. }
  443. static inline void text_update_xy(QemuConsole *s, int x, int y)
  444. {
  445. s->text_x[0] = MIN(s->text_x[0], x);
  446. s->text_x[1] = MAX(s->text_x[1], x);
  447. s->text_y[0] = MIN(s->text_y[0], y);
  448. s->text_y[1] = MAX(s->text_y[1], y);
  449. }
  450. static void invalidate_xy(QemuConsole *s, int x, int y)
  451. {
  452. if (!qemu_console_is_visible(s)) {
  453. return;
  454. }
  455. if (s->update_x0 > x * FONT_WIDTH)
  456. s->update_x0 = x * FONT_WIDTH;
  457. if (s->update_y0 > y * FONT_HEIGHT)
  458. s->update_y0 = y * FONT_HEIGHT;
  459. if (s->update_x1 < (x + 1) * FONT_WIDTH)
  460. s->update_x1 = (x + 1) * FONT_WIDTH;
  461. if (s->update_y1 < (y + 1) * FONT_HEIGHT)
  462. s->update_y1 = (y + 1) * FONT_HEIGHT;
  463. }
  464. static void update_xy(QemuConsole *s, int x, int y)
  465. {
  466. TextCell *c;
  467. int y1, y2;
  468. if (s->ds->have_text) {
  469. text_update_xy(s, x, y);
  470. }
  471. y1 = (s->y_base + y) % s->total_height;
  472. y2 = y1 - s->y_displayed;
  473. if (y2 < 0) {
  474. y2 += s->total_height;
  475. }
  476. if (y2 < s->height) {
  477. if (x >= s->width) {
  478. x = s->width - 1;
  479. }
  480. c = &s->cells[y1 * s->width + x];
  481. vga_putcharxy(s, x, y2, c->ch,
  482. &(c->t_attrib));
  483. invalidate_xy(s, x, y2);
  484. }
  485. }
  486. static void console_show_cursor(QemuConsole *s, int show)
  487. {
  488. TextCell *c;
  489. int y, y1;
  490. int x = s->x;
  491. if (s->ds->have_text) {
  492. s->cursor_invalidate = 1;
  493. }
  494. if (x >= s->width) {
  495. x = s->width - 1;
  496. }
  497. y1 = (s->y_base + s->y) % s->total_height;
  498. y = y1 - s->y_displayed;
  499. if (y < 0) {
  500. y += s->total_height;
  501. }
  502. if (y < s->height) {
  503. c = &s->cells[y1 * s->width + x];
  504. if (show && cursor_visible_phase) {
  505. TextAttributes t_attrib = s->t_attrib_default;
  506. t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
  507. vga_putcharxy(s, x, y, c->ch, &t_attrib);
  508. } else {
  509. vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
  510. }
  511. invalidate_xy(s, x, y);
  512. }
  513. }
  514. static void console_refresh(QemuConsole *s)
  515. {
  516. DisplaySurface *surface = qemu_console_surface(s);
  517. TextCell *c;
  518. int x, y, y1;
  519. if (s->ds->have_text) {
  520. s->text_x[0] = 0;
  521. s->text_y[0] = 0;
  522. s->text_x[1] = s->width - 1;
  523. s->text_y[1] = s->height - 1;
  524. s->cursor_invalidate = 1;
  525. }
  526. vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
  527. color_table_rgb[0][QEMU_COLOR_BLACK]);
  528. y1 = s->y_displayed;
  529. for (y = 0; y < s->height; y++) {
  530. c = s->cells + y1 * s->width;
  531. for (x = 0; x < s->width; x++) {
  532. vga_putcharxy(s, x, y, c->ch,
  533. &(c->t_attrib));
  534. c++;
  535. }
  536. if (++y1 == s->total_height) {
  537. y1 = 0;
  538. }
  539. }
  540. console_show_cursor(s, 1);
  541. dpy_gfx_update(s, 0, 0,
  542. surface_width(surface), surface_height(surface));
  543. }
  544. static void console_scroll(QemuConsole *s, int ydelta)
  545. {
  546. int i, y1;
  547. if (ydelta > 0) {
  548. for(i = 0; i < ydelta; i++) {
  549. if (s->y_displayed == s->y_base)
  550. break;
  551. if (++s->y_displayed == s->total_height)
  552. s->y_displayed = 0;
  553. }
  554. } else {
  555. ydelta = -ydelta;
  556. i = s->backscroll_height;
  557. if (i > s->total_height - s->height)
  558. i = s->total_height - s->height;
  559. y1 = s->y_base - i;
  560. if (y1 < 0)
  561. y1 += s->total_height;
  562. for(i = 0; i < ydelta; i++) {
  563. if (s->y_displayed == y1)
  564. break;
  565. if (--s->y_displayed < 0)
  566. s->y_displayed = s->total_height - 1;
  567. }
  568. }
  569. console_refresh(s);
  570. }
  571. static void console_put_lf(QemuConsole *s)
  572. {
  573. TextCell *c;
  574. int x, y1;
  575. s->y++;
  576. if (s->y >= s->height) {
  577. s->y = s->height - 1;
  578. if (s->y_displayed == s->y_base) {
  579. if (++s->y_displayed == s->total_height)
  580. s->y_displayed = 0;
  581. }
  582. if (++s->y_base == s->total_height)
  583. s->y_base = 0;
  584. if (s->backscroll_height < s->total_height)
  585. s->backscroll_height++;
  586. y1 = (s->y_base + s->height - 1) % s->total_height;
  587. c = &s->cells[y1 * s->width];
  588. for(x = 0; x < s->width; x++) {
  589. c->ch = ' ';
  590. c->t_attrib = s->t_attrib_default;
  591. c++;
  592. }
  593. if (s->y_displayed == s->y_base) {
  594. if (s->ds->have_text) {
  595. s->text_x[0] = 0;
  596. s->text_y[0] = 0;
  597. s->text_x[1] = s->width - 1;
  598. s->text_y[1] = s->height - 1;
  599. }
  600. vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
  601. s->width * FONT_WIDTH,
  602. (s->height - 1) * FONT_HEIGHT);
  603. vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
  604. s->width * FONT_WIDTH, FONT_HEIGHT,
  605. color_table_rgb[0][s->t_attrib_default.bgcol]);
  606. s->update_x0 = 0;
  607. s->update_y0 = 0;
  608. s->update_x1 = s->width * FONT_WIDTH;
  609. s->update_y1 = s->height * FONT_HEIGHT;
  610. }
  611. }
  612. }
  613. /* Set console attributes depending on the current escape codes.
  614. * NOTE: I know this code is not very efficient (checking every color for it
  615. * self) but it is more readable and better maintainable.
  616. */
  617. static void console_handle_escape(QemuConsole *s)
  618. {
  619. int i;
  620. for (i=0; i<s->nb_esc_params; i++) {
  621. switch (s->esc_params[i]) {
  622. case 0: /* reset all console attributes to default */
  623. s->t_attrib = s->t_attrib_default;
  624. break;
  625. case 1:
  626. s->t_attrib.bold = 1;
  627. break;
  628. case 4:
  629. s->t_attrib.uline = 1;
  630. break;
  631. case 5:
  632. s->t_attrib.blink = 1;
  633. break;
  634. case 7:
  635. s->t_attrib.invers = 1;
  636. break;
  637. case 8:
  638. s->t_attrib.unvisible = 1;
  639. break;
  640. case 22:
  641. s->t_attrib.bold = 0;
  642. break;
  643. case 24:
  644. s->t_attrib.uline = 0;
  645. break;
  646. case 25:
  647. s->t_attrib.blink = 0;
  648. break;
  649. case 27:
  650. s->t_attrib.invers = 0;
  651. break;
  652. case 28:
  653. s->t_attrib.unvisible = 0;
  654. break;
  655. /* set foreground color */
  656. case 30:
  657. s->t_attrib.fgcol = QEMU_COLOR_BLACK;
  658. break;
  659. case 31:
  660. s->t_attrib.fgcol = QEMU_COLOR_RED;
  661. break;
  662. case 32:
  663. s->t_attrib.fgcol = QEMU_COLOR_GREEN;
  664. break;
  665. case 33:
  666. s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
  667. break;
  668. case 34:
  669. s->t_attrib.fgcol = QEMU_COLOR_BLUE;
  670. break;
  671. case 35:
  672. s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
  673. break;
  674. case 36:
  675. s->t_attrib.fgcol = QEMU_COLOR_CYAN;
  676. break;
  677. case 37:
  678. s->t_attrib.fgcol = QEMU_COLOR_WHITE;
  679. break;
  680. /* set background color */
  681. case 40:
  682. s->t_attrib.bgcol = QEMU_COLOR_BLACK;
  683. break;
  684. case 41:
  685. s->t_attrib.bgcol = QEMU_COLOR_RED;
  686. break;
  687. case 42:
  688. s->t_attrib.bgcol = QEMU_COLOR_GREEN;
  689. break;
  690. case 43:
  691. s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
  692. break;
  693. case 44:
  694. s->t_attrib.bgcol = QEMU_COLOR_BLUE;
  695. break;
  696. case 45:
  697. s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
  698. break;
  699. case 46:
  700. s->t_attrib.bgcol = QEMU_COLOR_CYAN;
  701. break;
  702. case 47:
  703. s->t_attrib.bgcol = QEMU_COLOR_WHITE;
  704. break;
  705. }
  706. }
  707. }
  708. static void console_clear_xy(QemuConsole *s, int x, int y)
  709. {
  710. int y1 = (s->y_base + y) % s->total_height;
  711. if (x >= s->width) {
  712. x = s->width - 1;
  713. }
  714. TextCell *c = &s->cells[y1 * s->width + x];
  715. c->ch = ' ';
  716. c->t_attrib = s->t_attrib_default;
  717. update_xy(s, x, y);
  718. }
  719. static void console_put_one(QemuConsole *s, int ch)
  720. {
  721. TextCell *c;
  722. int y1;
  723. if (s->x >= s->width) {
  724. /* line wrap */
  725. s->x = 0;
  726. console_put_lf(s);
  727. }
  728. y1 = (s->y_base + s->y) % s->total_height;
  729. c = &s->cells[y1 * s->width + s->x];
  730. c->ch = ch;
  731. c->t_attrib = s->t_attrib;
  732. update_xy(s, s->x, s->y);
  733. s->x++;
  734. }
  735. static void console_respond_str(QemuConsole *s, const char *buf)
  736. {
  737. while (*buf) {
  738. console_put_one(s, *buf);
  739. buf++;
  740. }
  741. }
  742. /* set cursor, checking bounds */
  743. static void set_cursor(QemuConsole *s, int x, int y)
  744. {
  745. if (x < 0) {
  746. x = 0;
  747. }
  748. if (y < 0) {
  749. y = 0;
  750. }
  751. if (y >= s->height) {
  752. y = s->height - 1;
  753. }
  754. if (x >= s->width) {
  755. x = s->width - 1;
  756. }
  757. s->x = x;
  758. s->y = y;
  759. }
  760. static void console_putchar(QemuConsole *s, int ch)
  761. {
  762. int i;
  763. int x, y;
  764. char response[40];
  765. switch(s->state) {
  766. case TTY_STATE_NORM:
  767. switch(ch) {
  768. case '\r': /* carriage return */
  769. s->x = 0;
  770. break;
  771. case '\n': /* newline */
  772. console_put_lf(s);
  773. break;
  774. case '\b': /* backspace */
  775. if (s->x > 0)
  776. s->x--;
  777. break;
  778. case '\t': /* tabspace */
  779. if (s->x + (8 - (s->x % 8)) > s->width) {
  780. s->x = 0;
  781. console_put_lf(s);
  782. } else {
  783. s->x = s->x + (8 - (s->x % 8));
  784. }
  785. break;
  786. case '\a': /* alert aka. bell */
  787. /* TODO: has to be implemented */
  788. break;
  789. case 14:
  790. /* SI (shift in), character set 0 (ignored) */
  791. break;
  792. case 15:
  793. /* SO (shift out), character set 1 (ignored) */
  794. break;
  795. case 27: /* esc (introducing an escape sequence) */
  796. s->state = TTY_STATE_ESC;
  797. break;
  798. default:
  799. console_put_one(s, ch);
  800. break;
  801. }
  802. break;
  803. case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
  804. if (ch == '[') {
  805. for(i=0;i<MAX_ESC_PARAMS;i++)
  806. s->esc_params[i] = 0;
  807. s->nb_esc_params = 0;
  808. s->state = TTY_STATE_CSI;
  809. } else {
  810. s->state = TTY_STATE_NORM;
  811. }
  812. break;
  813. case TTY_STATE_CSI: /* handle escape sequence parameters */
  814. if (ch >= '0' && ch <= '9') {
  815. if (s->nb_esc_params < MAX_ESC_PARAMS) {
  816. int *param = &s->esc_params[s->nb_esc_params];
  817. int digit = (ch - '0');
  818. *param = (*param <= (INT_MAX - digit) / 10) ?
  819. *param * 10 + digit : INT_MAX;
  820. }
  821. } else {
  822. if (s->nb_esc_params < MAX_ESC_PARAMS)
  823. s->nb_esc_params++;
  824. if (ch == ';' || ch == '?') {
  825. break;
  826. }
  827. trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
  828. ch, s->nb_esc_params);
  829. s->state = TTY_STATE_NORM;
  830. switch(ch) {
  831. case 'A':
  832. /* move cursor up */
  833. if (s->esc_params[0] == 0) {
  834. s->esc_params[0] = 1;
  835. }
  836. set_cursor(s, s->x, s->y - s->esc_params[0]);
  837. break;
  838. case 'B':
  839. /* move cursor down */
  840. if (s->esc_params[0] == 0) {
  841. s->esc_params[0] = 1;
  842. }
  843. set_cursor(s, s->x, s->y + s->esc_params[0]);
  844. break;
  845. case 'C':
  846. /* move cursor right */
  847. if (s->esc_params[0] == 0) {
  848. s->esc_params[0] = 1;
  849. }
  850. set_cursor(s, s->x + s->esc_params[0], s->y);
  851. break;
  852. case 'D':
  853. /* move cursor left */
  854. if (s->esc_params[0] == 0) {
  855. s->esc_params[0] = 1;
  856. }
  857. set_cursor(s, s->x - s->esc_params[0], s->y);
  858. break;
  859. case 'G':
  860. /* move cursor to column */
  861. set_cursor(s, s->esc_params[0] - 1, s->y);
  862. break;
  863. case 'f':
  864. case 'H':
  865. /* move cursor to row, column */
  866. set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
  867. break;
  868. case 'J':
  869. switch (s->esc_params[0]) {
  870. case 0:
  871. /* clear to end of screen */
  872. for (y = s->y; y < s->height; y++) {
  873. for (x = 0; x < s->width; x++) {
  874. if (y == s->y && x < s->x) {
  875. continue;
  876. }
  877. console_clear_xy(s, x, y);
  878. }
  879. }
  880. break;
  881. case 1:
  882. /* clear from beginning of screen */
  883. for (y = 0; y <= s->y; y++) {
  884. for (x = 0; x < s->width; x++) {
  885. if (y == s->y && x > s->x) {
  886. break;
  887. }
  888. console_clear_xy(s, x, y);
  889. }
  890. }
  891. break;
  892. case 2:
  893. /* clear entire screen */
  894. for (y = 0; y <= s->height; y++) {
  895. for (x = 0; x < s->width; x++) {
  896. console_clear_xy(s, x, y);
  897. }
  898. }
  899. break;
  900. }
  901. break;
  902. case 'K':
  903. switch (s->esc_params[0]) {
  904. case 0:
  905. /* clear to eol */
  906. for(x = s->x; x < s->width; x++) {
  907. console_clear_xy(s, x, s->y);
  908. }
  909. break;
  910. case 1:
  911. /* clear from beginning of line */
  912. for (x = 0; x <= s->x && x < s->width; x++) {
  913. console_clear_xy(s, x, s->y);
  914. }
  915. break;
  916. case 2:
  917. /* clear entire line */
  918. for(x = 0; x < s->width; x++) {
  919. console_clear_xy(s, x, s->y);
  920. }
  921. break;
  922. }
  923. break;
  924. case 'm':
  925. console_handle_escape(s);
  926. break;
  927. case 'n':
  928. switch (s->esc_params[0]) {
  929. case 5:
  930. /* report console status (always succeed)*/
  931. console_respond_str(s, "\033[0n");
  932. break;
  933. case 6:
  934. /* report cursor position */
  935. sprintf(response, "\033[%d;%dR",
  936. (s->y_base + s->y) % s->total_height + 1,
  937. s->x + 1);
  938. console_respond_str(s, response);
  939. break;
  940. }
  941. break;
  942. case 's':
  943. /* save cursor position */
  944. s->x_saved = s->x;
  945. s->y_saved = s->y;
  946. break;
  947. case 'u':
  948. /* restore cursor position */
  949. s->x = s->x_saved;
  950. s->y = s->y_saved;
  951. break;
  952. default:
  953. trace_console_putchar_unhandled(ch);
  954. break;
  955. }
  956. break;
  957. }
  958. }
  959. }
  960. void console_select(unsigned int index)
  961. {
  962. DisplayChangeListener *dcl;
  963. QemuConsole *s;
  964. trace_console_select(index);
  965. s = qemu_console_lookup_by_index(index);
  966. if (s) {
  967. DisplayState *ds = s->ds;
  968. active_console = s;
  969. if (ds->have_gfx) {
  970. QLIST_FOREACH(dcl, &ds->listeners, next) {
  971. if (dcl->con != NULL) {
  972. continue;
  973. }
  974. if (dcl->ops->dpy_gfx_switch) {
  975. dcl->ops->dpy_gfx_switch(dcl, s->surface);
  976. }
  977. }
  978. if (s->surface) {
  979. dpy_gfx_update(s, 0, 0, surface_width(s->surface),
  980. surface_height(s->surface));
  981. }
  982. }
  983. if (ds->have_text) {
  984. dpy_text_resize(s, s->width, s->height);
  985. }
  986. text_console_update_cursor(NULL);
  987. }
  988. }
  989. typedef struct VCChardev {
  990. Chardev parent;
  991. QemuConsole *console;
  992. } VCChardev;
  993. #define TYPE_CHARDEV_VC "chardev-vc"
  994. #define VC_CHARDEV(obj) OBJECT_CHECK(VCChardev, (obj), TYPE_CHARDEV_VC)
  995. static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
  996. {
  997. VCChardev *drv = VC_CHARDEV(chr);
  998. QemuConsole *s = drv->console;
  999. int i;
  1000. if (!s->ds) {
  1001. return 0;
  1002. }
  1003. s->update_x0 = s->width * FONT_WIDTH;
  1004. s->update_y0 = s->height * FONT_HEIGHT;
  1005. s->update_x1 = 0;
  1006. s->update_y1 = 0;
  1007. console_show_cursor(s, 0);
  1008. for(i = 0; i < len; i++) {
  1009. console_putchar(s, buf[i]);
  1010. }
  1011. console_show_cursor(s, 1);
  1012. if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
  1013. dpy_gfx_update(s, s->update_x0, s->update_y0,
  1014. s->update_x1 - s->update_x0,
  1015. s->update_y1 - s->update_y0);
  1016. }
  1017. return len;
  1018. }
  1019. static void kbd_send_chars(void *opaque)
  1020. {
  1021. QemuConsole *s = opaque;
  1022. int len;
  1023. uint8_t buf[16];
  1024. len = qemu_chr_be_can_write(s->chr);
  1025. if (len > s->out_fifo.count)
  1026. len = s->out_fifo.count;
  1027. if (len > 0) {
  1028. if (len > sizeof(buf))
  1029. len = sizeof(buf);
  1030. qemu_fifo_read(&s->out_fifo, buf, len);
  1031. qemu_chr_be_write(s->chr, buf, len);
  1032. }
  1033. /* characters are pending: we send them a bit later (XXX:
  1034. horrible, should change char device API) */
  1035. if (s->out_fifo.count > 0) {
  1036. timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
  1037. }
  1038. }
  1039. /* called when an ascii key is pressed */
  1040. void kbd_put_keysym_console(QemuConsole *s, int keysym)
  1041. {
  1042. uint8_t buf[16], *q;
  1043. CharBackend *be;
  1044. int c;
  1045. if (!s || (s->console_type == GRAPHIC_CONSOLE))
  1046. return;
  1047. switch(keysym) {
  1048. case QEMU_KEY_CTRL_UP:
  1049. console_scroll(s, -1);
  1050. break;
  1051. case QEMU_KEY_CTRL_DOWN:
  1052. console_scroll(s, 1);
  1053. break;
  1054. case QEMU_KEY_CTRL_PAGEUP:
  1055. console_scroll(s, -10);
  1056. break;
  1057. case QEMU_KEY_CTRL_PAGEDOWN:
  1058. console_scroll(s, 10);
  1059. break;
  1060. default:
  1061. /* convert the QEMU keysym to VT100 key string */
  1062. q = buf;
  1063. if (keysym >= 0xe100 && keysym <= 0xe11f) {
  1064. *q++ = '\033';
  1065. *q++ = '[';
  1066. c = keysym - 0xe100;
  1067. if (c >= 10)
  1068. *q++ = '0' + (c / 10);
  1069. *q++ = '0' + (c % 10);
  1070. *q++ = '~';
  1071. } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
  1072. *q++ = '\033';
  1073. *q++ = '[';
  1074. *q++ = keysym & 0xff;
  1075. } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
  1076. vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
  1077. *q++ = '\n';
  1078. } else {
  1079. *q++ = keysym;
  1080. }
  1081. if (s->echo) {
  1082. vc_chr_write(s->chr, buf, q - buf);
  1083. }
  1084. be = s->chr->be;
  1085. if (be && be->chr_read) {
  1086. qemu_fifo_write(&s->out_fifo, buf, q - buf);
  1087. kbd_send_chars(s);
  1088. }
  1089. break;
  1090. }
  1091. }
  1092. static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
  1093. [Q_KEY_CODE_UP] = QEMU_KEY_UP,
  1094. [Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
  1095. [Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
  1096. [Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT,
  1097. [Q_KEY_CODE_HOME] = QEMU_KEY_HOME,
  1098. [Q_KEY_CODE_END] = QEMU_KEY_END,
  1099. [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
  1100. [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
  1101. [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
  1102. [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
  1103. };
  1104. static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
  1105. [Q_KEY_CODE_UP] = QEMU_KEY_CTRL_UP,
  1106. [Q_KEY_CODE_DOWN] = QEMU_KEY_CTRL_DOWN,
  1107. [Q_KEY_CODE_RIGHT] = QEMU_KEY_CTRL_RIGHT,
  1108. [Q_KEY_CODE_LEFT] = QEMU_KEY_CTRL_LEFT,
  1109. [Q_KEY_CODE_HOME] = QEMU_KEY_CTRL_HOME,
  1110. [Q_KEY_CODE_END] = QEMU_KEY_CTRL_END,
  1111. [Q_KEY_CODE_PGUP] = QEMU_KEY_CTRL_PAGEUP,
  1112. [Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN,
  1113. };
  1114. bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
  1115. {
  1116. int keysym;
  1117. keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
  1118. if (keysym == 0) {
  1119. return false;
  1120. }
  1121. kbd_put_keysym_console(s, keysym);
  1122. return true;
  1123. }
  1124. void kbd_put_string_console(QemuConsole *s, const char *str, int len)
  1125. {
  1126. int i;
  1127. for (i = 0; i < len && str[i]; i++) {
  1128. kbd_put_keysym_console(s, str[i]);
  1129. }
  1130. }
  1131. void kbd_put_keysym(int keysym)
  1132. {
  1133. kbd_put_keysym_console(active_console, keysym);
  1134. }
  1135. static void text_console_invalidate(void *opaque)
  1136. {
  1137. QemuConsole *s = (QemuConsole *) opaque;
  1138. if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
  1139. text_console_resize(s);
  1140. }
  1141. console_refresh(s);
  1142. }
  1143. static void text_console_update(void *opaque, console_ch_t *chardata)
  1144. {
  1145. QemuConsole *s = (QemuConsole *) opaque;
  1146. int i, j, src;
  1147. if (s->text_x[0] <= s->text_x[1]) {
  1148. src = (s->y_base + s->text_y[0]) * s->width;
  1149. chardata += s->text_y[0] * s->width;
  1150. for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
  1151. for (j = 0; j < s->width; j++, src++) {
  1152. console_write_ch(chardata ++,
  1153. ATTR2CHTYPE(s->cells[src].ch,
  1154. s->cells[src].t_attrib.fgcol,
  1155. s->cells[src].t_attrib.bgcol,
  1156. s->cells[src].t_attrib.bold));
  1157. }
  1158. dpy_text_update(s, s->text_x[0], s->text_y[0],
  1159. s->text_x[1] - s->text_x[0], i - s->text_y[0]);
  1160. s->text_x[0] = s->width;
  1161. s->text_y[0] = s->height;
  1162. s->text_x[1] = 0;
  1163. s->text_y[1] = 0;
  1164. }
  1165. if (s->cursor_invalidate) {
  1166. dpy_text_cursor(s, s->x, s->y);
  1167. s->cursor_invalidate = 0;
  1168. }
  1169. }
  1170. static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
  1171. uint32_t head)
  1172. {
  1173. Object *obj;
  1174. QemuConsole *s;
  1175. int i;
  1176. obj = object_new(TYPE_QEMU_CONSOLE);
  1177. s = QEMU_CONSOLE(obj);
  1178. s->head = head;
  1179. object_property_add_link(obj, "device", TYPE_DEVICE,
  1180. (Object **)&s->device,
  1181. object_property_allow_set_link,
  1182. OBJ_PROP_LINK_STRONG,
  1183. &error_abort);
  1184. object_property_add_uint32_ptr(obj, "head",
  1185. &s->head, &error_abort);
  1186. if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
  1187. (console_type == GRAPHIC_CONSOLE))) {
  1188. active_console = s;
  1189. }
  1190. s->ds = ds;
  1191. s->console_type = console_type;
  1192. if (QTAILQ_EMPTY(&consoles)) {
  1193. s->index = 0;
  1194. QTAILQ_INSERT_TAIL(&consoles, s, next);
  1195. } else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
  1196. QemuConsole *last = QTAILQ_LAST(&consoles);
  1197. s->index = last->index + 1;
  1198. QTAILQ_INSERT_TAIL(&consoles, s, next);
  1199. } else {
  1200. /*
  1201. * HACK: Put graphical consoles before text consoles.
  1202. *
  1203. * Only do that for coldplugged devices. After initial device
  1204. * initialization we will not renumber the consoles any more.
  1205. */
  1206. QemuConsole *c = QTAILQ_FIRST(&consoles);
  1207. while (QTAILQ_NEXT(c, next) != NULL &&
  1208. c->console_type == GRAPHIC_CONSOLE) {
  1209. c = QTAILQ_NEXT(c, next);
  1210. }
  1211. if (c->console_type == GRAPHIC_CONSOLE) {
  1212. /* have no text consoles */
  1213. s->index = c->index + 1;
  1214. QTAILQ_INSERT_AFTER(&consoles, c, s, next);
  1215. } else {
  1216. s->index = c->index;
  1217. QTAILQ_INSERT_BEFORE(c, s, next);
  1218. /* renumber text consoles */
  1219. for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
  1220. c->index = i;
  1221. }
  1222. }
  1223. }
  1224. return s;
  1225. }
  1226. static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
  1227. {
  1228. qemu_pixman_image_unref(surface->image);
  1229. surface->image = NULL;
  1230. surface->format = PIXMAN_x8r8g8b8;
  1231. surface->image = pixman_image_create_bits(surface->format,
  1232. width, height,
  1233. NULL, width * 4);
  1234. assert(surface->image != NULL);
  1235. surface->flags = QEMU_ALLOCATED_FLAG;
  1236. }
  1237. DisplaySurface *qemu_create_displaysurface(int width, int height)
  1238. {
  1239. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  1240. trace_displaysurface_create(surface, width, height);
  1241. qemu_alloc_display(surface, width, height);
  1242. return surface;
  1243. }
  1244. DisplaySurface *qemu_create_displaysurface_from(int width, int height,
  1245. pixman_format_code_t format,
  1246. int linesize, uint8_t *data)
  1247. {
  1248. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  1249. trace_displaysurface_create_from(surface, width, height, format);
  1250. surface->format = format;
  1251. surface->image = pixman_image_create_bits(surface->format,
  1252. width, height,
  1253. (void *)data, linesize);
  1254. assert(surface->image != NULL);
  1255. return surface;
  1256. }
  1257. DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
  1258. {
  1259. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  1260. trace_displaysurface_create_pixman(surface);
  1261. surface->format = pixman_image_get_format(image);
  1262. surface->image = pixman_image_ref(image);
  1263. return surface;
  1264. }
  1265. DisplaySurface *qemu_create_message_surface(int w, int h,
  1266. const char *msg)
  1267. {
  1268. DisplaySurface *surface = qemu_create_displaysurface(w, h);
  1269. pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
  1270. pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
  1271. pixman_image_t *glyph;
  1272. int len, x, y, i;
  1273. len = strlen(msg);
  1274. x = (w / FONT_WIDTH - len) / 2;
  1275. y = (h / FONT_HEIGHT - 1) / 2;
  1276. for (i = 0; i < len; i++) {
  1277. glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
  1278. qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
  1279. x+i, y, FONT_WIDTH, FONT_HEIGHT);
  1280. qemu_pixman_image_unref(glyph);
  1281. }
  1282. return surface;
  1283. }
  1284. void qemu_free_displaysurface(DisplaySurface *surface)
  1285. {
  1286. if (surface == NULL) {
  1287. return;
  1288. }
  1289. trace_displaysurface_free(surface);
  1290. qemu_pixman_image_unref(surface->image);
  1291. g_free(surface);
  1292. }
  1293. bool console_has_gl(QemuConsole *con)
  1294. {
  1295. return con->gl != NULL;
  1296. }
  1297. bool console_has_gl_dmabuf(QemuConsole *con)
  1298. {
  1299. return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
  1300. }
  1301. void register_displaychangelistener(DisplayChangeListener *dcl)
  1302. {
  1303. static const char nodev[] =
  1304. "This VM has no graphic display device.";
  1305. static DisplaySurface *dummy;
  1306. QemuConsole *con;
  1307. assert(!dcl->ds);
  1308. if (dcl->ops->dpy_gl_ctx_create) {
  1309. /* display has opengl support */
  1310. assert(dcl->con);
  1311. if (dcl->con->gl) {
  1312. fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
  1313. dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
  1314. exit(1);
  1315. }
  1316. dcl->con->gl = dcl;
  1317. }
  1318. trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
  1319. dcl->ds = get_alloc_displaystate();
  1320. QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
  1321. gui_setup_refresh(dcl->ds);
  1322. if (dcl->con) {
  1323. dcl->con->dcls++;
  1324. con = dcl->con;
  1325. } else {
  1326. con = active_console;
  1327. }
  1328. if (dcl->ops->dpy_gfx_switch) {
  1329. if (con) {
  1330. dcl->ops->dpy_gfx_switch(dcl, con->surface);
  1331. } else {
  1332. if (!dummy) {
  1333. dummy = qemu_create_message_surface(640, 480, nodev);
  1334. }
  1335. dcl->ops->dpy_gfx_switch(dcl, dummy);
  1336. }
  1337. }
  1338. text_console_update_cursor(NULL);
  1339. }
  1340. void update_displaychangelistener(DisplayChangeListener *dcl,
  1341. uint64_t interval)
  1342. {
  1343. DisplayState *ds = dcl->ds;
  1344. dcl->update_interval = interval;
  1345. if (!ds->refreshing && ds->update_interval > interval) {
  1346. timer_mod(ds->gui_timer, ds->last_update + interval);
  1347. }
  1348. }
  1349. void unregister_displaychangelistener(DisplayChangeListener *dcl)
  1350. {
  1351. DisplayState *ds = dcl->ds;
  1352. trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
  1353. if (dcl->con) {
  1354. dcl->con->dcls--;
  1355. }
  1356. QLIST_REMOVE(dcl, next);
  1357. dcl->ds = NULL;
  1358. gui_setup_refresh(ds);
  1359. }
  1360. static void dpy_set_ui_info_timer(void *opaque)
  1361. {
  1362. QemuConsole *con = opaque;
  1363. con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
  1364. }
  1365. bool dpy_ui_info_supported(QemuConsole *con)
  1366. {
  1367. return con->hw_ops->ui_info != NULL;
  1368. }
  1369. int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
  1370. {
  1371. assert(con != NULL);
  1372. if (!dpy_ui_info_supported(con)) {
  1373. return -1;
  1374. }
  1375. if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
  1376. /* nothing changed -- ignore */
  1377. return 0;
  1378. }
  1379. /*
  1380. * Typically we get a flood of these as the user resizes the window.
  1381. * Wait until the dust has settled (one second without updates), then
  1382. * go notify the guest.
  1383. */
  1384. con->ui_info = *info;
  1385. timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
  1386. return 0;
  1387. }
  1388. void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
  1389. {
  1390. DisplayState *s = con->ds;
  1391. DisplayChangeListener *dcl;
  1392. int width = w;
  1393. int height = h;
  1394. if (con->surface) {
  1395. width = surface_width(con->surface);
  1396. height = surface_height(con->surface);
  1397. }
  1398. x = MAX(x, 0);
  1399. y = MAX(y, 0);
  1400. x = MIN(x, width);
  1401. y = MIN(y, height);
  1402. w = MIN(w, width - x);
  1403. h = MIN(h, height - y);
  1404. if (!qemu_console_is_visible(con)) {
  1405. return;
  1406. }
  1407. QLIST_FOREACH(dcl, &s->listeners, next) {
  1408. if (con != (dcl->con ? dcl->con : active_console)) {
  1409. continue;
  1410. }
  1411. if (dcl->ops->dpy_gfx_update) {
  1412. dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
  1413. }
  1414. }
  1415. }
  1416. void dpy_gfx_update_full(QemuConsole *con)
  1417. {
  1418. if (!con->surface) {
  1419. return;
  1420. }
  1421. dpy_gfx_update(con, 0, 0,
  1422. surface_width(con->surface),
  1423. surface_height(con->surface));
  1424. }
  1425. void dpy_gfx_replace_surface(QemuConsole *con,
  1426. DisplaySurface *surface)
  1427. {
  1428. DisplayState *s = con->ds;
  1429. DisplaySurface *old_surface = con->surface;
  1430. DisplayChangeListener *dcl;
  1431. assert(old_surface != surface || surface == NULL);
  1432. con->surface = surface;
  1433. QLIST_FOREACH(dcl, &s->listeners, next) {
  1434. if (con != (dcl->con ? dcl->con : active_console)) {
  1435. continue;
  1436. }
  1437. if (dcl->ops->dpy_gfx_switch) {
  1438. dcl->ops->dpy_gfx_switch(dcl, surface);
  1439. }
  1440. }
  1441. qemu_free_displaysurface(old_surface);
  1442. }
  1443. bool dpy_gfx_check_format(QemuConsole *con,
  1444. pixman_format_code_t format)
  1445. {
  1446. DisplayChangeListener *dcl;
  1447. DisplayState *s = con->ds;
  1448. QLIST_FOREACH(dcl, &s->listeners, next) {
  1449. if (dcl->con && dcl->con != con) {
  1450. /* dcl bound to another console -> skip */
  1451. continue;
  1452. }
  1453. if (dcl->ops->dpy_gfx_check_format) {
  1454. if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
  1455. return false;
  1456. }
  1457. } else {
  1458. /* default is to whitelist native 32 bpp only */
  1459. if (format != qemu_default_pixman_format(32, true)) {
  1460. return false;
  1461. }
  1462. }
  1463. }
  1464. return true;
  1465. }
  1466. static void dpy_refresh(DisplayState *s)
  1467. {
  1468. DisplayChangeListener *dcl;
  1469. QLIST_FOREACH(dcl, &s->listeners, next) {
  1470. if (dcl->ops->dpy_refresh) {
  1471. dcl->ops->dpy_refresh(dcl);
  1472. }
  1473. }
  1474. }
  1475. void dpy_text_cursor(QemuConsole *con, int x, int y)
  1476. {
  1477. DisplayState *s = con->ds;
  1478. DisplayChangeListener *dcl;
  1479. if (!qemu_console_is_visible(con)) {
  1480. return;
  1481. }
  1482. QLIST_FOREACH(dcl, &s->listeners, next) {
  1483. if (con != (dcl->con ? dcl->con : active_console)) {
  1484. continue;
  1485. }
  1486. if (dcl->ops->dpy_text_cursor) {
  1487. dcl->ops->dpy_text_cursor(dcl, x, y);
  1488. }
  1489. }
  1490. }
  1491. void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
  1492. {
  1493. DisplayState *s = con->ds;
  1494. DisplayChangeListener *dcl;
  1495. if (!qemu_console_is_visible(con)) {
  1496. return;
  1497. }
  1498. QLIST_FOREACH(dcl, &s->listeners, next) {
  1499. if (con != (dcl->con ? dcl->con : active_console)) {
  1500. continue;
  1501. }
  1502. if (dcl->ops->dpy_text_update) {
  1503. dcl->ops->dpy_text_update(dcl, x, y, w, h);
  1504. }
  1505. }
  1506. }
  1507. void dpy_text_resize(QemuConsole *con, int w, int h)
  1508. {
  1509. DisplayState *s = con->ds;
  1510. DisplayChangeListener *dcl;
  1511. if (!qemu_console_is_visible(con)) {
  1512. return;
  1513. }
  1514. QLIST_FOREACH(dcl, &s->listeners, next) {
  1515. if (con != (dcl->con ? dcl->con : active_console)) {
  1516. continue;
  1517. }
  1518. if (dcl->ops->dpy_text_resize) {
  1519. dcl->ops->dpy_text_resize(dcl, w, h);
  1520. }
  1521. }
  1522. }
  1523. void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
  1524. {
  1525. DisplayState *s = con->ds;
  1526. DisplayChangeListener *dcl;
  1527. if (!qemu_console_is_visible(con)) {
  1528. return;
  1529. }
  1530. QLIST_FOREACH(dcl, &s->listeners, next) {
  1531. if (con != (dcl->con ? dcl->con : active_console)) {
  1532. continue;
  1533. }
  1534. if (dcl->ops->dpy_mouse_set) {
  1535. dcl->ops->dpy_mouse_set(dcl, x, y, on);
  1536. }
  1537. }
  1538. }
  1539. void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
  1540. {
  1541. DisplayState *s = con->ds;
  1542. DisplayChangeListener *dcl;
  1543. if (!qemu_console_is_visible(con)) {
  1544. return;
  1545. }
  1546. QLIST_FOREACH(dcl, &s->listeners, next) {
  1547. if (con != (dcl->con ? dcl->con : active_console)) {
  1548. continue;
  1549. }
  1550. if (dcl->ops->dpy_cursor_define) {
  1551. dcl->ops->dpy_cursor_define(dcl, cursor);
  1552. }
  1553. }
  1554. }
  1555. bool dpy_cursor_define_supported(QemuConsole *con)
  1556. {
  1557. DisplayState *s = con->ds;
  1558. DisplayChangeListener *dcl;
  1559. QLIST_FOREACH(dcl, &s->listeners, next) {
  1560. if (dcl->ops->dpy_cursor_define) {
  1561. return true;
  1562. }
  1563. }
  1564. return false;
  1565. }
  1566. QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
  1567. struct QEMUGLParams *qparams)
  1568. {
  1569. assert(con->gl);
  1570. return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
  1571. }
  1572. void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
  1573. {
  1574. assert(con->gl);
  1575. con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
  1576. }
  1577. int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
  1578. {
  1579. assert(con->gl);
  1580. return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
  1581. }
  1582. QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
  1583. {
  1584. assert(con->gl);
  1585. return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
  1586. }
  1587. void dpy_gl_scanout_disable(QemuConsole *con)
  1588. {
  1589. assert(con->gl);
  1590. if (con->gl->ops->dpy_gl_scanout_disable) {
  1591. con->gl->ops->dpy_gl_scanout_disable(con->gl);
  1592. } else {
  1593. con->gl->ops->dpy_gl_scanout_texture(con->gl, 0, false, 0, 0,
  1594. 0, 0, 0, 0);
  1595. }
  1596. }
  1597. void dpy_gl_scanout_texture(QemuConsole *con,
  1598. uint32_t backing_id,
  1599. bool backing_y_0_top,
  1600. uint32_t backing_width,
  1601. uint32_t backing_height,
  1602. uint32_t x, uint32_t y,
  1603. uint32_t width, uint32_t height)
  1604. {
  1605. assert(con->gl);
  1606. con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
  1607. backing_y_0_top,
  1608. backing_width, backing_height,
  1609. x, y, width, height);
  1610. }
  1611. void dpy_gl_scanout_dmabuf(QemuConsole *con,
  1612. QemuDmaBuf *dmabuf)
  1613. {
  1614. assert(con->gl);
  1615. con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
  1616. }
  1617. void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
  1618. bool have_hot, uint32_t hot_x, uint32_t hot_y)
  1619. {
  1620. assert(con->gl);
  1621. if (con->gl->ops->dpy_gl_cursor_dmabuf) {
  1622. con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
  1623. have_hot, hot_x, hot_y);
  1624. }
  1625. }
  1626. void dpy_gl_cursor_position(QemuConsole *con,
  1627. uint32_t pos_x, uint32_t pos_y)
  1628. {
  1629. assert(con->gl);
  1630. if (con->gl->ops->dpy_gl_cursor_position) {
  1631. con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
  1632. }
  1633. }
  1634. void dpy_gl_release_dmabuf(QemuConsole *con,
  1635. QemuDmaBuf *dmabuf)
  1636. {
  1637. assert(con->gl);
  1638. if (con->gl->ops->dpy_gl_release_dmabuf) {
  1639. con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
  1640. }
  1641. }
  1642. void dpy_gl_update(QemuConsole *con,
  1643. uint32_t x, uint32_t y, uint32_t w, uint32_t h)
  1644. {
  1645. assert(con->gl);
  1646. con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
  1647. }
  1648. /***********************************************************/
  1649. /* register display */
  1650. /* console.c internal use only */
  1651. static DisplayState *get_alloc_displaystate(void)
  1652. {
  1653. if (!display_state) {
  1654. display_state = g_new0(DisplayState, 1);
  1655. cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
  1656. text_console_update_cursor, NULL);
  1657. }
  1658. return display_state;
  1659. }
  1660. /*
  1661. * Called by main(), after creating QemuConsoles
  1662. * and before initializing ui (sdl/vnc/...).
  1663. */
  1664. DisplayState *init_displaystate(void)
  1665. {
  1666. gchar *name;
  1667. QemuConsole *con;
  1668. get_alloc_displaystate();
  1669. QTAILQ_FOREACH(con, &consoles, next) {
  1670. if (con->console_type != GRAPHIC_CONSOLE &&
  1671. con->ds == NULL) {
  1672. text_console_do_init(con->chr, display_state);
  1673. }
  1674. /* Hook up into the qom tree here (not in new_console()), once
  1675. * all QemuConsoles are created and the order / numbering
  1676. * doesn't change any more */
  1677. name = g_strdup_printf("console[%d]", con->index);
  1678. object_property_add_child(container_get(object_get_root(), "/backend"),
  1679. name, OBJECT(con), &error_abort);
  1680. g_free(name);
  1681. }
  1682. return display_state;
  1683. }
  1684. void graphic_console_set_hwops(QemuConsole *con,
  1685. const GraphicHwOps *hw_ops,
  1686. void *opaque)
  1687. {
  1688. con->hw_ops = hw_ops;
  1689. con->hw = opaque;
  1690. }
  1691. QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
  1692. const GraphicHwOps *hw_ops,
  1693. void *opaque)
  1694. {
  1695. static const char noinit[] =
  1696. "Guest has not initialized the display (yet).";
  1697. int width = 640;
  1698. int height = 480;
  1699. QemuConsole *s;
  1700. DisplayState *ds;
  1701. DisplaySurface *surface;
  1702. ds = get_alloc_displaystate();
  1703. s = qemu_console_lookup_unused();
  1704. if (s) {
  1705. trace_console_gfx_reuse(s->index);
  1706. if (s->surface) {
  1707. width = surface_width(s->surface);
  1708. height = surface_height(s->surface);
  1709. }
  1710. } else {
  1711. trace_console_gfx_new();
  1712. s = new_console(ds, GRAPHIC_CONSOLE, head);
  1713. s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
  1714. dpy_set_ui_info_timer, s);
  1715. }
  1716. graphic_console_set_hwops(s, hw_ops, opaque);
  1717. if (dev) {
  1718. object_property_set_link(OBJECT(s), OBJECT(dev), "device",
  1719. &error_abort);
  1720. }
  1721. surface = qemu_create_message_surface(width, height, noinit);
  1722. dpy_gfx_replace_surface(s, surface);
  1723. return s;
  1724. }
  1725. static const GraphicHwOps unused_ops = {
  1726. /* no callbacks */
  1727. };
  1728. void graphic_console_close(QemuConsole *con)
  1729. {
  1730. static const char unplugged[] =
  1731. "Guest display has been unplugged";
  1732. DisplaySurface *surface;
  1733. int width = 640;
  1734. int height = 480;
  1735. if (con->surface) {
  1736. width = surface_width(con->surface);
  1737. height = surface_height(con->surface);
  1738. }
  1739. trace_console_gfx_close(con->index);
  1740. object_property_set_link(OBJECT(con), NULL, "device", &error_abort);
  1741. graphic_console_set_hwops(con, &unused_ops, NULL);
  1742. if (con->gl) {
  1743. dpy_gl_scanout_disable(con);
  1744. }
  1745. surface = qemu_create_message_surface(width, height, unplugged);
  1746. dpy_gfx_replace_surface(con, surface);
  1747. }
  1748. QemuConsole *qemu_console_lookup_by_index(unsigned int index)
  1749. {
  1750. QemuConsole *con;
  1751. QTAILQ_FOREACH(con, &consoles, next) {
  1752. if (con->index == index) {
  1753. return con;
  1754. }
  1755. }
  1756. return NULL;
  1757. }
  1758. QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
  1759. {
  1760. QemuConsole *con;
  1761. Object *obj;
  1762. uint32_t h;
  1763. QTAILQ_FOREACH(con, &consoles, next) {
  1764. obj = object_property_get_link(OBJECT(con),
  1765. "device", &error_abort);
  1766. if (DEVICE(obj) != dev) {
  1767. continue;
  1768. }
  1769. h = object_property_get_uint(OBJECT(con),
  1770. "head", &error_abort);
  1771. if (h != head) {
  1772. continue;
  1773. }
  1774. return con;
  1775. }
  1776. return NULL;
  1777. }
  1778. QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
  1779. uint32_t head, Error **errp)
  1780. {
  1781. DeviceState *dev;
  1782. QemuConsole *con;
  1783. dev = qdev_find_recursive(sysbus_get_default(), device_id);
  1784. if (dev == NULL) {
  1785. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  1786. "Device '%s' not found", device_id);
  1787. return NULL;
  1788. }
  1789. con = qemu_console_lookup_by_device(dev, head);
  1790. if (con == NULL) {
  1791. error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
  1792. device_id, head);
  1793. return NULL;
  1794. }
  1795. return con;
  1796. }
  1797. QemuConsole *qemu_console_lookup_unused(void)
  1798. {
  1799. QemuConsole *con;
  1800. Object *obj;
  1801. QTAILQ_FOREACH(con, &consoles, next) {
  1802. if (con->hw_ops != &unused_ops) {
  1803. continue;
  1804. }
  1805. obj = object_property_get_link(OBJECT(con),
  1806. "device", &error_abort);
  1807. if (obj != NULL) {
  1808. continue;
  1809. }
  1810. return con;
  1811. }
  1812. return NULL;
  1813. }
  1814. bool qemu_console_is_visible(QemuConsole *con)
  1815. {
  1816. return (con == active_console) || (con->dcls > 0);
  1817. }
  1818. bool qemu_console_is_graphic(QemuConsole *con)
  1819. {
  1820. if (con == NULL) {
  1821. con = active_console;
  1822. }
  1823. return con && (con->console_type == GRAPHIC_CONSOLE);
  1824. }
  1825. bool qemu_console_is_fixedsize(QemuConsole *con)
  1826. {
  1827. if (con == NULL) {
  1828. con = active_console;
  1829. }
  1830. return con && (con->console_type != TEXT_CONSOLE);
  1831. }
  1832. bool qemu_console_is_gl_blocked(QemuConsole *con)
  1833. {
  1834. assert(con != NULL);
  1835. return con->gl_block;
  1836. }
  1837. char *qemu_console_get_label(QemuConsole *con)
  1838. {
  1839. if (con->console_type == GRAPHIC_CONSOLE) {
  1840. if (con->device) {
  1841. return g_strdup(object_get_typename(con->device));
  1842. }
  1843. return g_strdup("VGA");
  1844. } else {
  1845. if (con->chr && con->chr->label) {
  1846. return g_strdup(con->chr->label);
  1847. }
  1848. return g_strdup_printf("vc%d", con->index);
  1849. }
  1850. }
  1851. int qemu_console_get_index(QemuConsole *con)
  1852. {
  1853. if (con == NULL) {
  1854. con = active_console;
  1855. }
  1856. return con ? con->index : -1;
  1857. }
  1858. uint32_t qemu_console_get_head(QemuConsole *con)
  1859. {
  1860. if (con == NULL) {
  1861. con = active_console;
  1862. }
  1863. return con ? con->head : -1;
  1864. }
  1865. QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
  1866. {
  1867. assert(con != NULL);
  1868. return &con->ui_info;
  1869. }
  1870. int qemu_console_get_width(QemuConsole *con, int fallback)
  1871. {
  1872. if (con == NULL) {
  1873. con = active_console;
  1874. }
  1875. return con ? surface_width(con->surface) : fallback;
  1876. }
  1877. int qemu_console_get_height(QemuConsole *con, int fallback)
  1878. {
  1879. if (con == NULL) {
  1880. con = active_console;
  1881. }
  1882. return con ? surface_height(con->surface) : fallback;
  1883. }
  1884. static void vc_chr_set_echo(Chardev *chr, bool echo)
  1885. {
  1886. VCChardev *drv = VC_CHARDEV(chr);
  1887. QemuConsole *s = drv->console;
  1888. s->echo = echo;
  1889. }
  1890. static void text_console_update_cursor_timer(void)
  1891. {
  1892. timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
  1893. + CONSOLE_CURSOR_PERIOD / 2);
  1894. }
  1895. static void text_console_update_cursor(void *opaque)
  1896. {
  1897. QemuConsole *s;
  1898. int count = 0;
  1899. cursor_visible_phase = !cursor_visible_phase;
  1900. QTAILQ_FOREACH(s, &consoles, next) {
  1901. if (qemu_console_is_graphic(s) ||
  1902. !qemu_console_is_visible(s)) {
  1903. continue;
  1904. }
  1905. count++;
  1906. graphic_hw_invalidate(s);
  1907. }
  1908. if (count) {
  1909. text_console_update_cursor_timer();
  1910. }
  1911. }
  1912. static const GraphicHwOps text_console_ops = {
  1913. .invalidate = text_console_invalidate,
  1914. .text_update = text_console_update,
  1915. };
  1916. static void text_console_do_init(Chardev *chr, DisplayState *ds)
  1917. {
  1918. VCChardev *drv = VC_CHARDEV(chr);
  1919. QemuConsole *s = drv->console;
  1920. int g_width = 80 * FONT_WIDTH;
  1921. int g_height = 24 * FONT_HEIGHT;
  1922. s->out_fifo.buf = s->out_fifo_buf;
  1923. s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
  1924. s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
  1925. s->ds = ds;
  1926. s->y_displayed = 0;
  1927. s->y_base = 0;
  1928. s->total_height = DEFAULT_BACKSCROLL;
  1929. s->x = 0;
  1930. s->y = 0;
  1931. if (!s->surface) {
  1932. if (active_console && active_console->surface) {
  1933. g_width = surface_width(active_console->surface);
  1934. g_height = surface_height(active_console->surface);
  1935. }
  1936. s->surface = qemu_create_displaysurface(g_width, g_height);
  1937. }
  1938. s->hw_ops = &text_console_ops;
  1939. s->hw = s;
  1940. /* Set text attribute defaults */
  1941. s->t_attrib_default.bold = 0;
  1942. s->t_attrib_default.uline = 0;
  1943. s->t_attrib_default.blink = 0;
  1944. s->t_attrib_default.invers = 0;
  1945. s->t_attrib_default.unvisible = 0;
  1946. s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
  1947. s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
  1948. /* set current text attributes to default */
  1949. s->t_attrib = s->t_attrib_default;
  1950. text_console_resize(s);
  1951. if (chr->label) {
  1952. char msg[128];
  1953. int len;
  1954. s->t_attrib.bgcol = QEMU_COLOR_BLUE;
  1955. len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
  1956. vc_chr_write(chr, (uint8_t *)msg, len);
  1957. s->t_attrib = s->t_attrib_default;
  1958. }
  1959. qemu_chr_be_event(chr, CHR_EVENT_OPENED);
  1960. }
  1961. static void vc_chr_open(Chardev *chr,
  1962. ChardevBackend *backend,
  1963. bool *be_opened,
  1964. Error **errp)
  1965. {
  1966. ChardevVC *vc = backend->u.vc.data;
  1967. VCChardev *drv = VC_CHARDEV(chr);
  1968. QemuConsole *s;
  1969. unsigned width = 0;
  1970. unsigned height = 0;
  1971. if (vc->has_width) {
  1972. width = vc->width;
  1973. } else if (vc->has_cols) {
  1974. width = vc->cols * FONT_WIDTH;
  1975. }
  1976. if (vc->has_height) {
  1977. height = vc->height;
  1978. } else if (vc->has_rows) {
  1979. height = vc->rows * FONT_HEIGHT;
  1980. }
  1981. trace_console_txt_new(width, height);
  1982. if (width == 0 || height == 0) {
  1983. s = new_console(NULL, TEXT_CONSOLE, 0);
  1984. } else {
  1985. s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
  1986. s->surface = qemu_create_displaysurface(width, height);
  1987. }
  1988. if (!s) {
  1989. error_setg(errp, "cannot create text console");
  1990. return;
  1991. }
  1992. s->chr = chr;
  1993. drv->console = s;
  1994. if (display_state) {
  1995. text_console_do_init(chr, display_state);
  1996. }
  1997. /* console/chardev init sometimes completes elsewhere in a 2nd
  1998. * stage, so defer OPENED events until they are fully initialized
  1999. */
  2000. *be_opened = false;
  2001. }
  2002. void qemu_console_resize(QemuConsole *s, int width, int height)
  2003. {
  2004. DisplaySurface *surface;
  2005. assert(s->console_type == GRAPHIC_CONSOLE);
  2006. if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
  2007. pixman_image_get_width(s->surface->image) == width &&
  2008. pixman_image_get_height(s->surface->image) == height) {
  2009. return;
  2010. }
  2011. surface = qemu_create_displaysurface(width, height);
  2012. dpy_gfx_replace_surface(s, surface);
  2013. }
  2014. DisplaySurface *qemu_console_surface(QemuConsole *console)
  2015. {
  2016. return console->surface;
  2017. }
  2018. PixelFormat qemu_default_pixelformat(int bpp)
  2019. {
  2020. pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
  2021. PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
  2022. return pf;
  2023. }
  2024. static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
  2025. void qemu_display_register(QemuDisplay *ui)
  2026. {
  2027. assert(ui->type < DISPLAY_TYPE__MAX);
  2028. dpys[ui->type] = ui;
  2029. }
  2030. bool qemu_display_find_default(DisplayOptions *opts)
  2031. {
  2032. static DisplayType prio[] = {
  2033. DISPLAY_TYPE_GTK,
  2034. DISPLAY_TYPE_SDL,
  2035. DISPLAY_TYPE_COCOA
  2036. };
  2037. int i;
  2038. for (i = 0; i < ARRAY_SIZE(prio); i++) {
  2039. if (dpys[prio[i]] == NULL) {
  2040. ui_module_load_one(DisplayType_str(prio[i]));
  2041. }
  2042. if (dpys[prio[i]] == NULL) {
  2043. continue;
  2044. }
  2045. opts->type = prio[i];
  2046. return true;
  2047. }
  2048. return false;
  2049. }
  2050. void qemu_display_early_init(DisplayOptions *opts)
  2051. {
  2052. assert(opts->type < DISPLAY_TYPE__MAX);
  2053. if (opts->type == DISPLAY_TYPE_NONE) {
  2054. return;
  2055. }
  2056. if (dpys[opts->type] == NULL) {
  2057. ui_module_load_one(DisplayType_str(opts->type));
  2058. }
  2059. if (dpys[opts->type] == NULL) {
  2060. error_report("Display '%s' is not available.",
  2061. DisplayType_str(opts->type));
  2062. exit(1);
  2063. }
  2064. if (dpys[opts->type]->early_init) {
  2065. dpys[opts->type]->early_init(opts);
  2066. }
  2067. }
  2068. void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
  2069. {
  2070. assert(opts->type < DISPLAY_TYPE__MAX);
  2071. if (opts->type == DISPLAY_TYPE_NONE) {
  2072. return;
  2073. }
  2074. assert(dpys[opts->type] != NULL);
  2075. dpys[opts->type]->init(ds, opts);
  2076. }
  2077. void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
  2078. {
  2079. int val;
  2080. ChardevVC *vc;
  2081. backend->type = CHARDEV_BACKEND_KIND_VC;
  2082. vc = backend->u.vc.data = g_new0(ChardevVC, 1);
  2083. qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
  2084. val = qemu_opt_get_number(opts, "width", 0);
  2085. if (val != 0) {
  2086. vc->has_width = true;
  2087. vc->width = val;
  2088. }
  2089. val = qemu_opt_get_number(opts, "height", 0);
  2090. if (val != 0) {
  2091. vc->has_height = true;
  2092. vc->height = val;
  2093. }
  2094. val = qemu_opt_get_number(opts, "cols", 0);
  2095. if (val != 0) {
  2096. vc->has_cols = true;
  2097. vc->cols = val;
  2098. }
  2099. val = qemu_opt_get_number(opts, "rows", 0);
  2100. if (val != 0) {
  2101. vc->has_rows = true;
  2102. vc->rows = val;
  2103. }
  2104. }
  2105. static const TypeInfo qemu_console_info = {
  2106. .name = TYPE_QEMU_CONSOLE,
  2107. .parent = TYPE_OBJECT,
  2108. .instance_size = sizeof(QemuConsole),
  2109. .class_size = sizeof(QemuConsoleClass),
  2110. };
  2111. static void char_vc_class_init(ObjectClass *oc, void *data)
  2112. {
  2113. ChardevClass *cc = CHARDEV_CLASS(oc);
  2114. cc->parse = qemu_chr_parse_vc;
  2115. cc->open = vc_chr_open;
  2116. cc->chr_write = vc_chr_write;
  2117. cc->chr_set_echo = vc_chr_set_echo;
  2118. }
  2119. static const TypeInfo char_vc_type_info = {
  2120. .name = TYPE_CHARDEV_VC,
  2121. .parent = TYPE_CHARDEV,
  2122. .instance_size = sizeof(VCChardev),
  2123. .class_init = char_vc_class_init,
  2124. };
  2125. void qemu_console_early_init(void)
  2126. {
  2127. /* set the default vc driver */
  2128. if (!object_class_by_name(TYPE_CHARDEV_VC)) {
  2129. type_register(&char_vc_type_info);
  2130. }
  2131. }
  2132. static void register_types(void)
  2133. {
  2134. type_register_static(&qemu_console_info);
  2135. }
  2136. type_init(register_types);