2
0

console.c 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640
  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 "qapi/visitor.h"
  30. #include "qemu/coroutine.h"
  31. #include "qemu/error-report.h"
  32. #include "qemu/main-loop.h"
  33. #include "qemu/module.h"
  34. #include "qemu/option.h"
  35. #include "chardev/char.h"
  36. #include "trace.h"
  37. #include "exec/memory.h"
  38. #include "qom/object.h"
  39. #include "console-priv.h"
  40. OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT)
  41. typedef struct QemuGraphicConsole {
  42. QemuConsole parent;
  43. Object *device;
  44. uint32_t head;
  45. QEMUCursor *cursor;
  46. int cursor_x, cursor_y;
  47. bool cursor_on;
  48. } QemuGraphicConsole;
  49. typedef QemuConsoleClass QemuGraphicConsoleClass;
  50. OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE)
  51. struct DisplayState {
  52. QEMUTimer *gui_timer;
  53. uint64_t last_update;
  54. uint64_t update_interval;
  55. bool refreshing;
  56. QLIST_HEAD(, DisplayChangeListener) listeners;
  57. };
  58. static DisplayState *display_state;
  59. static QTAILQ_HEAD(, QemuConsole) consoles =
  60. QTAILQ_HEAD_INITIALIZER(consoles);
  61. static void dpy_refresh(DisplayState *s);
  62. static DisplayState *get_alloc_displaystate(void);
  63. static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
  64. static bool console_compatible_with(QemuConsole *con,
  65. DisplayChangeListener *dcl, Error **errp);
  66. static QemuConsole *qemu_graphic_console_lookup_unused(void);
  67. static void dpy_set_ui_info_timer(void *opaque);
  68. static void gui_update(void *opaque)
  69. {
  70. uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
  71. uint64_t dcl_interval;
  72. DisplayState *ds = opaque;
  73. DisplayChangeListener *dcl;
  74. ds->refreshing = true;
  75. dpy_refresh(ds);
  76. ds->refreshing = false;
  77. QLIST_FOREACH(dcl, &ds->listeners, next) {
  78. dcl_interval = dcl->update_interval ?
  79. dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
  80. if (interval > dcl_interval) {
  81. interval = dcl_interval;
  82. }
  83. }
  84. if (ds->update_interval != interval) {
  85. ds->update_interval = interval;
  86. trace_console_refresh(interval);
  87. }
  88. ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
  89. timer_mod(ds->gui_timer, ds->last_update + interval);
  90. }
  91. static void gui_setup_refresh(DisplayState *ds)
  92. {
  93. DisplayChangeListener *dcl;
  94. bool need_timer = false;
  95. QLIST_FOREACH(dcl, &ds->listeners, next) {
  96. if (dcl->ops->dpy_refresh != NULL) {
  97. need_timer = true;
  98. }
  99. }
  100. if (need_timer && ds->gui_timer == NULL) {
  101. ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
  102. timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
  103. }
  104. if (!need_timer && ds->gui_timer != NULL) {
  105. timer_free(ds->gui_timer);
  106. ds->gui_timer = NULL;
  107. }
  108. }
  109. void graphic_hw_update_done(QemuConsole *con)
  110. {
  111. if (con) {
  112. qemu_co_enter_all(&con->dump_queue, NULL);
  113. }
  114. }
  115. void graphic_hw_update(QemuConsole *con)
  116. {
  117. bool async = false;
  118. if (!con) {
  119. return;
  120. }
  121. if (con->hw_ops->gfx_update) {
  122. con->hw_ops->gfx_update(con->hw);
  123. async = con->hw_ops->gfx_update_async;
  124. }
  125. if (!async) {
  126. graphic_hw_update_done(con);
  127. }
  128. }
  129. static void graphic_hw_update_bh(void *con)
  130. {
  131. graphic_hw_update(con);
  132. }
  133. void qemu_console_co_wait_update(QemuConsole *con)
  134. {
  135. if (qemu_co_queue_empty(&con->dump_queue)) {
  136. /* Defer the update, it will restart the pending coroutines */
  137. aio_bh_schedule_oneshot(qemu_get_aio_context(),
  138. graphic_hw_update_bh, con);
  139. }
  140. qemu_co_queue_wait(&con->dump_queue, NULL);
  141. }
  142. static void graphic_hw_gl_unblock_timer(void *opaque)
  143. {
  144. warn_report("console: no gl-unblock within one second");
  145. }
  146. void graphic_hw_gl_block(QemuConsole *con, bool block)
  147. {
  148. uint64_t timeout;
  149. assert(con != NULL);
  150. if (block) {
  151. con->gl_block++;
  152. } else {
  153. con->gl_block--;
  154. }
  155. assert(con->gl_block >= 0);
  156. if (!con->hw_ops->gl_block) {
  157. return;
  158. }
  159. if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
  160. return;
  161. }
  162. con->hw_ops->gl_block(con->hw, block);
  163. if (block) {
  164. timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
  165. timeout += 1000; /* one sec */
  166. timer_mod(con->gl_unblock_timer, timeout);
  167. } else {
  168. timer_del(con->gl_unblock_timer);
  169. }
  170. }
  171. int qemu_console_get_window_id(QemuConsole *con)
  172. {
  173. return con->window_id;
  174. }
  175. void qemu_console_set_window_id(QemuConsole *con, int window_id)
  176. {
  177. con->window_id = window_id;
  178. }
  179. void graphic_hw_invalidate(QemuConsole *con)
  180. {
  181. if (con && con->hw_ops->invalidate) {
  182. con->hw_ops->invalidate(con->hw);
  183. }
  184. }
  185. void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
  186. {
  187. if (con && con->hw_ops->text_update) {
  188. con->hw_ops->text_update(con->hw, chardata);
  189. }
  190. }
  191. static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
  192. struct DisplaySurface *new_surface,
  193. bool update)
  194. {
  195. if (dcl->ops->dpy_gfx_switch) {
  196. dcl->ops->dpy_gfx_switch(dcl, new_surface);
  197. }
  198. if (update && dcl->ops->dpy_gfx_update) {
  199. dcl->ops->dpy_gfx_update(dcl, 0, 0,
  200. surface_width(new_surface),
  201. surface_height(new_surface));
  202. }
  203. }
  204. static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface)
  205. {
  206. if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) {
  207. con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface);
  208. }
  209. }
  210. static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface)
  211. {
  212. if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) {
  213. con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface);
  214. }
  215. }
  216. static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface,
  217. int x, int y, int w, int h)
  218. {
  219. if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) {
  220. con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h);
  221. }
  222. }
  223. static void displaychangelistener_display_console(DisplayChangeListener *dcl,
  224. Error **errp)
  225. {
  226. static const char nodev[] =
  227. "This VM has no graphic display device.";
  228. static DisplaySurface *dummy;
  229. QemuConsole *con = dcl->con;
  230. if (!con || !console_compatible_with(con, dcl, errp)) {
  231. if (!dummy) {
  232. dummy = qemu_create_placeholder_surface(640, 480, nodev);
  233. }
  234. if (con) {
  235. dpy_gfx_create_texture(con, dummy);
  236. }
  237. displaychangelistener_gfx_switch(dcl, dummy, TRUE);
  238. return;
  239. }
  240. dpy_gfx_create_texture(con, con->surface);
  241. displaychangelistener_gfx_switch(dcl, con->surface,
  242. con->scanout.kind == SCANOUT_SURFACE);
  243. if (con->scanout.kind == SCANOUT_DMABUF &&
  244. displaychangelistener_has_dmabuf(dcl)) {
  245. dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
  246. } else if (con->scanout.kind == SCANOUT_TEXTURE &&
  247. dcl->ops->dpy_gl_scanout_texture) {
  248. dcl->ops->dpy_gl_scanout_texture(dcl,
  249. con->scanout.texture.backing_id,
  250. con->scanout.texture.backing_y_0_top,
  251. con->scanout.texture.backing_width,
  252. con->scanout.texture.backing_height,
  253. con->scanout.texture.x,
  254. con->scanout.texture.y,
  255. con->scanout.texture.width,
  256. con->scanout.texture.height,
  257. con->scanout.texture.d3d_tex2d);
  258. }
  259. }
  260. void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
  261. {
  262. qemu_text_console_handle_keysym(s, keysym);
  263. }
  264. static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
  265. [Q_KEY_CODE_UP] = QEMU_KEY_UP,
  266. [Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
  267. [Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
  268. [Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT,
  269. [Q_KEY_CODE_HOME] = QEMU_KEY_HOME,
  270. [Q_KEY_CODE_END] = QEMU_KEY_END,
  271. [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
  272. [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
  273. [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
  274. [Q_KEY_CODE_TAB] = QEMU_KEY_TAB,
  275. [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
  276. };
  277. static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
  278. [Q_KEY_CODE_UP] = QEMU_KEY_CTRL_UP,
  279. [Q_KEY_CODE_DOWN] = QEMU_KEY_CTRL_DOWN,
  280. [Q_KEY_CODE_RIGHT] = QEMU_KEY_CTRL_RIGHT,
  281. [Q_KEY_CODE_LEFT] = QEMU_KEY_CTRL_LEFT,
  282. [Q_KEY_CODE_HOME] = QEMU_KEY_CTRL_HOME,
  283. [Q_KEY_CODE_END] = QEMU_KEY_CTRL_END,
  284. [Q_KEY_CODE_PGUP] = QEMU_KEY_CTRL_PAGEUP,
  285. [Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN,
  286. };
  287. bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
  288. {
  289. int keysym;
  290. keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
  291. if (keysym == 0) {
  292. return false;
  293. }
  294. qemu_text_console_put_keysym(s, keysym);
  295. return true;
  296. }
  297. void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
  298. {
  299. int i;
  300. for (i = 0; i < len && str[i]; i++) {
  301. qemu_text_console_put_keysym(s, str[i]);
  302. }
  303. }
  304. static void
  305. qemu_console_register(QemuConsole *c)
  306. {
  307. int i;
  308. if (QTAILQ_EMPTY(&consoles)) {
  309. c->index = 0;
  310. QTAILQ_INSERT_TAIL(&consoles, c, next);
  311. } else if (!QEMU_IS_GRAPHIC_CONSOLE(c) || phase_check(PHASE_MACHINE_READY)) {
  312. QemuConsole *last = QTAILQ_LAST(&consoles);
  313. c->index = last->index + 1;
  314. QTAILQ_INSERT_TAIL(&consoles, c, next);
  315. } else {
  316. /*
  317. * HACK: Put graphical consoles before text consoles.
  318. *
  319. * Only do that for coldplugged devices. After initial device
  320. * initialization we will not renumber the consoles any more.
  321. */
  322. QemuConsole *it = QTAILQ_FIRST(&consoles);
  323. while (QTAILQ_NEXT(it, next) != NULL && QEMU_IS_GRAPHIC_CONSOLE(it)) {
  324. it = QTAILQ_NEXT(it, next);
  325. }
  326. if (QEMU_IS_GRAPHIC_CONSOLE(it)) {
  327. /* have no text consoles */
  328. c->index = it->index + 1;
  329. QTAILQ_INSERT_AFTER(&consoles, it, c, next);
  330. } else {
  331. c->index = it->index;
  332. QTAILQ_INSERT_BEFORE(it, c, next);
  333. /* renumber text consoles */
  334. for (i = c->index + 1; it != NULL; it = QTAILQ_NEXT(it, next), i++) {
  335. it->index = i;
  336. }
  337. }
  338. }
  339. }
  340. static void
  341. qemu_console_finalize(Object *obj)
  342. {
  343. QemuConsole *c = QEMU_CONSOLE(obj);
  344. /* TODO: check this code path, and unregister from consoles */
  345. g_clear_pointer(&c->surface, qemu_free_displaysurface);
  346. g_clear_pointer(&c->gl_unblock_timer, timer_free);
  347. g_clear_pointer(&c->ui_timer, timer_free);
  348. }
  349. static void
  350. qemu_console_class_init(ObjectClass *oc, void *data)
  351. {
  352. }
  353. static void
  354. qemu_console_init(Object *obj)
  355. {
  356. QemuConsole *c = QEMU_CONSOLE(obj);
  357. DisplayState *ds = get_alloc_displaystate();
  358. qemu_co_queue_init(&c->dump_queue);
  359. c->ds = ds;
  360. c->window_id = -1;
  361. c->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
  362. dpy_set_ui_info_timer, c);
  363. qemu_console_register(c);
  364. }
  365. static void
  366. qemu_graphic_console_finalize(Object *obj)
  367. {
  368. QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
  369. g_clear_pointer(&c->device, object_unref);
  370. }
  371. static void
  372. qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
  373. void *opaque, Error **errp)
  374. {
  375. QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
  376. visit_type_uint32(v, name, &c->head, errp);
  377. }
  378. static void
  379. qemu_graphic_console_class_init(ObjectClass *oc, void *data)
  380. {
  381. object_class_property_add_link(oc, "device", TYPE_DEVICE,
  382. offsetof(QemuGraphicConsole, device),
  383. object_property_allow_set_link,
  384. OBJ_PROP_LINK_STRONG);
  385. object_class_property_add(oc, "head", "uint32",
  386. qemu_graphic_console_prop_get_head,
  387. NULL, NULL, NULL);
  388. }
  389. static void
  390. qemu_graphic_console_init(Object *obj)
  391. {
  392. }
  393. #ifdef WIN32
  394. void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
  395. HANDLE h, uint32_t offset)
  396. {
  397. assert(!surface->handle);
  398. surface->handle = h;
  399. surface->handle_offset = offset;
  400. }
  401. static void
  402. win32_pixman_image_destroy(pixman_image_t *image, void *data)
  403. {
  404. DisplaySurface *surface = data;
  405. if (!surface->handle) {
  406. return;
  407. }
  408. assert(surface->handle_offset == 0);
  409. qemu_win32_map_free(
  410. pixman_image_get_data(surface->image),
  411. surface->handle,
  412. &error_warn
  413. );
  414. }
  415. #endif
  416. DisplaySurface *qemu_create_displaysurface(int width, int height)
  417. {
  418. DisplaySurface *surface;
  419. void *bits = NULL;
  420. #ifdef WIN32
  421. HANDLE handle = NULL;
  422. #endif
  423. trace_displaysurface_create(width, height);
  424. #ifdef WIN32
  425. bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
  426. #endif
  427. surface = qemu_create_displaysurface_from(
  428. width, height,
  429. PIXMAN_x8r8g8b8,
  430. width * 4, bits
  431. );
  432. surface->flags = QEMU_ALLOCATED_FLAG;
  433. #ifdef WIN32
  434. qemu_displaysurface_win32_set_handle(surface, handle, 0);
  435. #endif
  436. return surface;
  437. }
  438. DisplaySurface *qemu_create_displaysurface_from(int width, int height,
  439. pixman_format_code_t format,
  440. int linesize, uint8_t *data)
  441. {
  442. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  443. trace_displaysurface_create_from(surface, width, height, format);
  444. surface->image = pixman_image_create_bits(format,
  445. width, height,
  446. (void *)data, linesize);
  447. assert(surface->image != NULL);
  448. #ifdef WIN32
  449. pixman_image_set_destroy_function(surface->image,
  450. win32_pixman_image_destroy, surface);
  451. #endif
  452. return surface;
  453. }
  454. DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
  455. {
  456. DisplaySurface *surface = g_new0(DisplaySurface, 1);
  457. trace_displaysurface_create_pixman(surface);
  458. surface->image = pixman_image_ref(image);
  459. return surface;
  460. }
  461. DisplaySurface *qemu_create_placeholder_surface(int w, int h,
  462. const char *msg)
  463. {
  464. DisplaySurface *surface = qemu_create_displaysurface(w, h);
  465. #ifdef CONFIG_PIXMAN
  466. pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
  467. pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
  468. pixman_image_t *glyph;
  469. int len, x, y, i;
  470. len = strlen(msg);
  471. x = (w / FONT_WIDTH - len) / 2;
  472. y = (h / FONT_HEIGHT - 1) / 2;
  473. for (i = 0; i < len; i++) {
  474. glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
  475. qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
  476. x+i, y, FONT_WIDTH, FONT_HEIGHT);
  477. qemu_pixman_image_unref(glyph);
  478. }
  479. #endif
  480. surface->flags |= QEMU_PLACEHOLDER_FLAG;
  481. return surface;
  482. }
  483. void qemu_free_displaysurface(DisplaySurface *surface)
  484. {
  485. if (surface == NULL) {
  486. return;
  487. }
  488. trace_displaysurface_free(surface);
  489. qemu_pixman_image_unref(surface->image);
  490. g_free(surface);
  491. }
  492. bool console_has_gl(QemuConsole *con)
  493. {
  494. return con->gl != NULL;
  495. }
  496. static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
  497. {
  498. if (dcl->ops->dpy_has_dmabuf) {
  499. return dcl->ops->dpy_has_dmabuf(dcl);
  500. }
  501. if (dcl->ops->dpy_gl_scanout_dmabuf) {
  502. return true;
  503. }
  504. return false;
  505. }
  506. static bool console_compatible_with(QemuConsole *con,
  507. DisplayChangeListener *dcl, Error **errp)
  508. {
  509. int flags;
  510. flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
  511. if (console_has_gl(con) &&
  512. !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
  513. error_setg(errp, "Display %s is incompatible with the GL context",
  514. dcl->ops->dpy_name);
  515. return false;
  516. }
  517. if (flags & GRAPHIC_FLAGS_GL &&
  518. !console_has_gl(con)) {
  519. error_setg(errp, "The console requires a GL context.");
  520. return false;
  521. }
  522. if (flags & GRAPHIC_FLAGS_DMABUF &&
  523. !displaychangelistener_has_dmabuf(dcl)) {
  524. error_setg(errp, "The console requires display DMABUF support.");
  525. return false;
  526. }
  527. return true;
  528. }
  529. void console_handle_touch_event(QemuConsole *con,
  530. struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
  531. uint64_t num_slot,
  532. int width, int height,
  533. double x, double y,
  534. InputMultiTouchType type,
  535. Error **errp)
  536. {
  537. struct touch_slot *slot;
  538. bool needs_sync = false;
  539. int update;
  540. int i;
  541. if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
  542. error_setg(errp,
  543. "Unexpected touch slot number: % " PRId64" >= %d",
  544. num_slot, INPUT_EVENT_SLOTS_MAX);
  545. return;
  546. }
  547. slot = &touch_slots[num_slot];
  548. slot->x = x;
  549. slot->y = y;
  550. if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
  551. slot->tracking_id = num_slot;
  552. }
  553. for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
  554. if (i == num_slot) {
  555. update = type;
  556. } else {
  557. update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
  558. }
  559. slot = &touch_slots[i];
  560. if (slot->tracking_id == -1) {
  561. continue;
  562. }
  563. if (update == INPUT_MULTI_TOUCH_TYPE_END) {
  564. slot->tracking_id = -1;
  565. qemu_input_queue_mtt(con, update, i, slot->tracking_id);
  566. needs_sync = true;
  567. } else {
  568. qemu_input_queue_mtt(con, update, i, slot->tracking_id);
  569. qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
  570. qemu_input_queue_mtt_abs(con,
  571. INPUT_AXIS_X, (int) slot->x,
  572. 0, width,
  573. i, slot->tracking_id);
  574. qemu_input_queue_mtt_abs(con,
  575. INPUT_AXIS_Y, (int) slot->y,
  576. 0, height,
  577. i, slot->tracking_id);
  578. needs_sync = true;
  579. }
  580. }
  581. if (needs_sync) {
  582. qemu_input_event_sync();
  583. }
  584. }
  585. void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
  586. {
  587. /* display has opengl support */
  588. assert(con);
  589. if (con->gl) {
  590. error_report("The console already has an OpenGL context.");
  591. exit(1);
  592. }
  593. con->gl = gl;
  594. }
  595. static void
  596. dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
  597. {
  598. if (con && con->cursor && dcl->ops->dpy_cursor_define) {
  599. dcl->ops->dpy_cursor_define(dcl, con->cursor);
  600. }
  601. if (con && dcl->ops->dpy_mouse_set) {
  602. dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
  603. }
  604. }
  605. void register_displaychangelistener(DisplayChangeListener *dcl)
  606. {
  607. assert(!dcl->ds);
  608. trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
  609. dcl->ds = get_alloc_displaystate();
  610. QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
  611. gui_setup_refresh(dcl->ds);
  612. if (dcl->con) {
  613. dcl->con->dcls++;
  614. }
  615. displaychangelistener_display_console(dcl, &error_fatal);
  616. if (QEMU_IS_GRAPHIC_CONSOLE(dcl->con)) {
  617. dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(dcl->con));
  618. } else if (QEMU_IS_TEXT_CONSOLE(dcl->con)) {
  619. qemu_text_console_update_size(QEMU_TEXT_CONSOLE(dcl->con));
  620. }
  621. qemu_text_console_update_cursor();
  622. }
  623. void update_displaychangelistener(DisplayChangeListener *dcl,
  624. uint64_t interval)
  625. {
  626. DisplayState *ds = dcl->ds;
  627. dcl->update_interval = interval;
  628. if (!ds->refreshing && ds->update_interval > interval) {
  629. timer_mod(ds->gui_timer, ds->last_update + interval);
  630. }
  631. }
  632. void unregister_displaychangelistener(DisplayChangeListener *dcl)
  633. {
  634. DisplayState *ds = dcl->ds;
  635. trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
  636. if (dcl->con) {
  637. dcl->con->dcls--;
  638. }
  639. QLIST_REMOVE(dcl, next);
  640. dcl->ds = NULL;
  641. gui_setup_refresh(ds);
  642. }
  643. static void dpy_set_ui_info_timer(void *opaque)
  644. {
  645. QemuConsole *con = opaque;
  646. uint32_t head = qemu_console_get_head(con);
  647. con->hw_ops->ui_info(con->hw, head, &con->ui_info);
  648. }
  649. bool dpy_ui_info_supported(const QemuConsole *con)
  650. {
  651. if (con == NULL) {
  652. return false;
  653. }
  654. return con->hw_ops->ui_info != NULL;
  655. }
  656. const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
  657. {
  658. assert(dpy_ui_info_supported(con));
  659. return &con->ui_info;
  660. }
  661. int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
  662. {
  663. if (!dpy_ui_info_supported(con)) {
  664. return -1;
  665. }
  666. if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
  667. /* nothing changed -- ignore */
  668. return 0;
  669. }
  670. /*
  671. * Typically we get a flood of these as the user resizes the window.
  672. * Wait until the dust has settled (one second without updates), then
  673. * go notify the guest.
  674. */
  675. con->ui_info = *info;
  676. timer_mod(con->ui_timer,
  677. qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
  678. return 0;
  679. }
  680. void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
  681. {
  682. DisplayState *s = con->ds;
  683. DisplayChangeListener *dcl;
  684. int width = qemu_console_get_width(con, x + w);
  685. int height = qemu_console_get_height(con, y + h);
  686. x = MAX(x, 0);
  687. y = MAX(y, 0);
  688. x = MIN(x, width);
  689. y = MIN(y, height);
  690. w = MIN(w, width - x);
  691. h = MIN(h, height - y);
  692. if (!qemu_console_is_visible(con)) {
  693. return;
  694. }
  695. dpy_gfx_update_texture(con, con->surface, x, y, w, h);
  696. QLIST_FOREACH(dcl, &s->listeners, next) {
  697. if (con != dcl->con) {
  698. continue;
  699. }
  700. if (dcl->ops->dpy_gfx_update) {
  701. dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
  702. }
  703. }
  704. }
  705. void dpy_gfx_update_full(QemuConsole *con)
  706. {
  707. int w = qemu_console_get_width(con, 0);
  708. int h = qemu_console_get_height(con, 0);
  709. dpy_gfx_update(con, 0, 0, w, h);
  710. }
  711. void dpy_gfx_replace_surface(QemuConsole *con,
  712. DisplaySurface *surface)
  713. {
  714. static const char placeholder_msg[] = "Display output is not active.";
  715. DisplayState *s = con->ds;
  716. DisplaySurface *old_surface = con->surface;
  717. DisplaySurface *new_surface = surface;
  718. DisplayChangeListener *dcl;
  719. int width;
  720. int height;
  721. if (!surface) {
  722. if (old_surface) {
  723. width = surface_width(old_surface);
  724. height = surface_height(old_surface);
  725. } else {
  726. width = 640;
  727. height = 480;
  728. }
  729. new_surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
  730. }
  731. assert(old_surface != new_surface);
  732. con->scanout.kind = SCANOUT_SURFACE;
  733. con->surface = new_surface;
  734. dpy_gfx_create_texture(con, new_surface);
  735. QLIST_FOREACH(dcl, &s->listeners, next) {
  736. if (con != dcl->con) {
  737. continue;
  738. }
  739. displaychangelistener_gfx_switch(dcl, new_surface, surface ? FALSE : TRUE);
  740. }
  741. dpy_gfx_destroy_texture(con, old_surface);
  742. qemu_free_displaysurface(old_surface);
  743. }
  744. bool dpy_gfx_check_format(QemuConsole *con,
  745. pixman_format_code_t format)
  746. {
  747. DisplayChangeListener *dcl;
  748. DisplayState *s = con->ds;
  749. QLIST_FOREACH(dcl, &s->listeners, next) {
  750. if (dcl->con && dcl->con != con) {
  751. /* dcl bound to another console -> skip */
  752. continue;
  753. }
  754. if (dcl->ops->dpy_gfx_check_format) {
  755. if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
  756. return false;
  757. }
  758. } else {
  759. /* default is to allow native 32 bpp only */
  760. if (format != qemu_default_pixman_format(32, true)) {
  761. return false;
  762. }
  763. }
  764. }
  765. return true;
  766. }
  767. static void dpy_refresh(DisplayState *s)
  768. {
  769. DisplayChangeListener *dcl;
  770. QLIST_FOREACH(dcl, &s->listeners, next) {
  771. if (dcl->ops->dpy_refresh) {
  772. dcl->ops->dpy_refresh(dcl);
  773. }
  774. }
  775. }
  776. void dpy_text_cursor(QemuConsole *con, int x, int y)
  777. {
  778. DisplayState *s = con->ds;
  779. DisplayChangeListener *dcl;
  780. if (!qemu_console_is_visible(con)) {
  781. return;
  782. }
  783. QLIST_FOREACH(dcl, &s->listeners, next) {
  784. if (con != dcl->con) {
  785. continue;
  786. }
  787. if (dcl->ops->dpy_text_cursor) {
  788. dcl->ops->dpy_text_cursor(dcl, x, y);
  789. }
  790. }
  791. }
  792. void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
  793. {
  794. DisplayState *s = con->ds;
  795. DisplayChangeListener *dcl;
  796. if (!qemu_console_is_visible(con)) {
  797. return;
  798. }
  799. QLIST_FOREACH(dcl, &s->listeners, next) {
  800. if (con != dcl->con) {
  801. continue;
  802. }
  803. if (dcl->ops->dpy_text_update) {
  804. dcl->ops->dpy_text_update(dcl, x, y, w, h);
  805. }
  806. }
  807. }
  808. void dpy_text_resize(QemuConsole *con, int w, int h)
  809. {
  810. DisplayState *s = con->ds;
  811. DisplayChangeListener *dcl;
  812. if (!qemu_console_is_visible(con)) {
  813. return;
  814. }
  815. QLIST_FOREACH(dcl, &s->listeners, next) {
  816. if (con != dcl->con) {
  817. continue;
  818. }
  819. if (dcl->ops->dpy_text_resize) {
  820. dcl->ops->dpy_text_resize(dcl, w, h);
  821. }
  822. }
  823. }
  824. void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
  825. {
  826. QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
  827. DisplayState *s = c->ds;
  828. DisplayChangeListener *dcl;
  829. con->cursor_x = x;
  830. con->cursor_y = y;
  831. con->cursor_on = on;
  832. if (!qemu_console_is_visible(c)) {
  833. return;
  834. }
  835. QLIST_FOREACH(dcl, &s->listeners, next) {
  836. if (c != dcl->con) {
  837. continue;
  838. }
  839. if (dcl->ops->dpy_mouse_set) {
  840. dcl->ops->dpy_mouse_set(dcl, x, y, on);
  841. }
  842. }
  843. }
  844. void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
  845. {
  846. QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
  847. DisplayState *s = c->ds;
  848. DisplayChangeListener *dcl;
  849. cursor_unref(con->cursor);
  850. con->cursor = cursor_ref(cursor);
  851. if (!qemu_console_is_visible(c)) {
  852. return;
  853. }
  854. QLIST_FOREACH(dcl, &s->listeners, next) {
  855. if (c != dcl->con) {
  856. continue;
  857. }
  858. if (dcl->ops->dpy_cursor_define) {
  859. dcl->ops->dpy_cursor_define(dcl, cursor);
  860. }
  861. }
  862. }
  863. QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
  864. struct QEMUGLParams *qparams)
  865. {
  866. assert(con->gl);
  867. return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
  868. }
  869. void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
  870. {
  871. assert(con->gl);
  872. con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
  873. }
  874. int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
  875. {
  876. assert(con->gl);
  877. return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
  878. }
  879. void dpy_gl_scanout_disable(QemuConsole *con)
  880. {
  881. DisplayState *s = con->ds;
  882. DisplayChangeListener *dcl;
  883. if (con->scanout.kind != SCANOUT_SURFACE) {
  884. con->scanout.kind = SCANOUT_NONE;
  885. }
  886. QLIST_FOREACH(dcl, &s->listeners, next) {
  887. if (con != dcl->con) {
  888. continue;
  889. }
  890. if (dcl->ops->dpy_gl_scanout_disable) {
  891. dcl->ops->dpy_gl_scanout_disable(dcl);
  892. }
  893. }
  894. }
  895. void dpy_gl_scanout_texture(QemuConsole *con,
  896. uint32_t backing_id,
  897. bool backing_y_0_top,
  898. uint32_t backing_width,
  899. uint32_t backing_height,
  900. uint32_t x, uint32_t y,
  901. uint32_t width, uint32_t height,
  902. void *d3d_tex2d)
  903. {
  904. DisplayState *s = con->ds;
  905. DisplayChangeListener *dcl;
  906. con->scanout.kind = SCANOUT_TEXTURE;
  907. con->scanout.texture = (ScanoutTexture) {
  908. backing_id, backing_y_0_top, backing_width, backing_height,
  909. x, y, width, height, d3d_tex2d,
  910. };
  911. QLIST_FOREACH(dcl, &s->listeners, next) {
  912. if (con != dcl->con) {
  913. continue;
  914. }
  915. if (dcl->ops->dpy_gl_scanout_texture) {
  916. dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
  917. backing_y_0_top,
  918. backing_width, backing_height,
  919. x, y, width, height,
  920. d3d_tex2d);
  921. }
  922. }
  923. }
  924. void dpy_gl_scanout_dmabuf(QemuConsole *con,
  925. QemuDmaBuf *dmabuf)
  926. {
  927. DisplayState *s = con->ds;
  928. DisplayChangeListener *dcl;
  929. con->scanout.kind = SCANOUT_DMABUF;
  930. con->scanout.dmabuf = dmabuf;
  931. QLIST_FOREACH(dcl, &s->listeners, next) {
  932. if (con != dcl->con) {
  933. continue;
  934. }
  935. if (dcl->ops->dpy_gl_scanout_dmabuf) {
  936. dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
  937. }
  938. }
  939. }
  940. void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
  941. bool have_hot, uint32_t hot_x, uint32_t hot_y)
  942. {
  943. DisplayState *s = con->ds;
  944. DisplayChangeListener *dcl;
  945. QLIST_FOREACH(dcl, &s->listeners, next) {
  946. if (con != dcl->con) {
  947. continue;
  948. }
  949. if (dcl->ops->dpy_gl_cursor_dmabuf) {
  950. dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
  951. have_hot, hot_x, hot_y);
  952. }
  953. }
  954. }
  955. void dpy_gl_cursor_position(QemuConsole *con,
  956. uint32_t pos_x, uint32_t pos_y)
  957. {
  958. DisplayState *s = con->ds;
  959. DisplayChangeListener *dcl;
  960. QLIST_FOREACH(dcl, &s->listeners, next) {
  961. if (con != dcl->con) {
  962. continue;
  963. }
  964. if (dcl->ops->dpy_gl_cursor_position) {
  965. dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
  966. }
  967. }
  968. }
  969. void dpy_gl_release_dmabuf(QemuConsole *con,
  970. QemuDmaBuf *dmabuf)
  971. {
  972. DisplayState *s = con->ds;
  973. DisplayChangeListener *dcl;
  974. QLIST_FOREACH(dcl, &s->listeners, next) {
  975. if (con != dcl->con) {
  976. continue;
  977. }
  978. if (dcl->ops->dpy_gl_release_dmabuf) {
  979. dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
  980. }
  981. }
  982. }
  983. void dpy_gl_update(QemuConsole *con,
  984. uint32_t x, uint32_t y, uint32_t w, uint32_t h)
  985. {
  986. DisplayState *s = con->ds;
  987. DisplayChangeListener *dcl;
  988. assert(con->gl);
  989. graphic_hw_gl_block(con, true);
  990. QLIST_FOREACH(dcl, &s->listeners, next) {
  991. if (con != dcl->con) {
  992. continue;
  993. }
  994. if (dcl->ops->dpy_gl_update) {
  995. dcl->ops->dpy_gl_update(dcl, x, y, w, h);
  996. }
  997. }
  998. graphic_hw_gl_block(con, false);
  999. }
  1000. /***********************************************************/
  1001. /* register display */
  1002. /* console.c internal use only */
  1003. static DisplayState *get_alloc_displaystate(void)
  1004. {
  1005. if (!display_state) {
  1006. display_state = g_new0(DisplayState, 1);
  1007. }
  1008. return display_state;
  1009. }
  1010. /*
  1011. * Called by main(), after creating QemuConsoles
  1012. * and before initializing ui (sdl/vnc/...).
  1013. */
  1014. DisplayState *init_displaystate(void)
  1015. {
  1016. gchar *name;
  1017. QemuConsole *con;
  1018. QTAILQ_FOREACH(con, &consoles, next) {
  1019. /* Hook up into the qom tree here (not in object_new()), once
  1020. * all QemuConsoles are created and the order / numbering
  1021. * doesn't change any more */
  1022. name = g_strdup_printf("console[%d]", con->index);
  1023. object_property_add_child(container_get(object_get_root(), "/backend"),
  1024. name, OBJECT(con));
  1025. g_free(name);
  1026. }
  1027. return display_state;
  1028. }
  1029. void graphic_console_set_hwops(QemuConsole *con,
  1030. const GraphicHwOps *hw_ops,
  1031. void *opaque)
  1032. {
  1033. con->hw_ops = hw_ops;
  1034. con->hw = opaque;
  1035. }
  1036. QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
  1037. const GraphicHwOps *hw_ops,
  1038. void *opaque)
  1039. {
  1040. static const char noinit[] =
  1041. "Guest has not initialized the display (yet).";
  1042. int width = 640;
  1043. int height = 480;
  1044. QemuConsole *s;
  1045. DisplaySurface *surface;
  1046. s = qemu_graphic_console_lookup_unused();
  1047. if (s) {
  1048. trace_console_gfx_reuse(s->index);
  1049. width = qemu_console_get_width(s, 0);
  1050. height = qemu_console_get_height(s, 0);
  1051. } else {
  1052. trace_console_gfx_new();
  1053. s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE);
  1054. }
  1055. QEMU_GRAPHIC_CONSOLE(s)->head = head;
  1056. graphic_console_set_hwops(s, hw_ops, opaque);
  1057. if (dev) {
  1058. object_property_set_link(OBJECT(s), "device", OBJECT(dev),
  1059. &error_abort);
  1060. }
  1061. surface = qemu_create_placeholder_surface(width, height, noinit);
  1062. dpy_gfx_replace_surface(s, surface);
  1063. s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
  1064. graphic_hw_gl_unblock_timer, s);
  1065. return s;
  1066. }
  1067. static const GraphicHwOps unused_ops = {
  1068. /* no callbacks */
  1069. };
  1070. void graphic_console_close(QemuConsole *con)
  1071. {
  1072. static const char unplugged[] =
  1073. "Guest display has been unplugged";
  1074. DisplaySurface *surface;
  1075. int width = qemu_console_get_width(con, 640);
  1076. int height = qemu_console_get_height(con, 480);
  1077. trace_console_gfx_close(con->index);
  1078. object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
  1079. graphic_console_set_hwops(con, &unused_ops, NULL);
  1080. if (con->gl) {
  1081. dpy_gl_scanout_disable(con);
  1082. }
  1083. surface = qemu_create_placeholder_surface(width, height, unplugged);
  1084. dpy_gfx_replace_surface(con, surface);
  1085. }
  1086. QemuConsole *qemu_console_lookup_default(void)
  1087. {
  1088. QemuConsole *con;
  1089. QTAILQ_FOREACH(con, &consoles, next) {
  1090. if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
  1091. return con;
  1092. }
  1093. }
  1094. return QTAILQ_FIRST(&consoles);
  1095. }
  1096. QemuConsole *qemu_console_lookup_by_index(unsigned int index)
  1097. {
  1098. QemuConsole *con;
  1099. QTAILQ_FOREACH(con, &consoles, next) {
  1100. if (con->index == index) {
  1101. return con;
  1102. }
  1103. }
  1104. return NULL;
  1105. }
  1106. QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
  1107. {
  1108. QemuConsole *con;
  1109. Object *obj;
  1110. uint32_t h;
  1111. QTAILQ_FOREACH(con, &consoles, next) {
  1112. obj = object_property_get_link(OBJECT(con),
  1113. "device", &error_abort);
  1114. if (DEVICE(obj) != dev) {
  1115. continue;
  1116. }
  1117. h = object_property_get_uint(OBJECT(con),
  1118. "head", &error_abort);
  1119. if (h != head) {
  1120. continue;
  1121. }
  1122. return con;
  1123. }
  1124. return NULL;
  1125. }
  1126. QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
  1127. uint32_t head, Error **errp)
  1128. {
  1129. DeviceState *dev;
  1130. QemuConsole *con;
  1131. dev = qdev_find_recursive(sysbus_get_default(), device_id);
  1132. if (dev == NULL) {
  1133. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  1134. "Device '%s' not found", device_id);
  1135. return NULL;
  1136. }
  1137. con = qemu_console_lookup_by_device(dev, head);
  1138. if (con == NULL) {
  1139. error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
  1140. device_id, head);
  1141. return NULL;
  1142. }
  1143. return con;
  1144. }
  1145. static QemuConsole *qemu_graphic_console_lookup_unused(void)
  1146. {
  1147. QemuConsole *con;
  1148. Object *obj;
  1149. QTAILQ_FOREACH(con, &consoles, next) {
  1150. if (!QEMU_IS_GRAPHIC_CONSOLE(con) || con->hw_ops != &unused_ops) {
  1151. continue;
  1152. }
  1153. obj = object_property_get_link(OBJECT(con),
  1154. "device", &error_abort);
  1155. if (obj != NULL) {
  1156. continue;
  1157. }
  1158. return con;
  1159. }
  1160. return NULL;
  1161. }
  1162. QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
  1163. {
  1164. return QEMU_IS_GRAPHIC_CONSOLE(con) ? QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
  1165. }
  1166. bool qemu_console_is_visible(QemuConsole *con)
  1167. {
  1168. return con->dcls > 0;
  1169. }
  1170. bool qemu_console_is_graphic(QemuConsole *con)
  1171. {
  1172. return con && QEMU_IS_GRAPHIC_CONSOLE(con);
  1173. }
  1174. bool qemu_console_is_fixedsize(QemuConsole *con)
  1175. {
  1176. return con && (QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con));
  1177. }
  1178. bool qemu_console_is_gl_blocked(QemuConsole *con)
  1179. {
  1180. assert(con != NULL);
  1181. return con->gl_block;
  1182. }
  1183. static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c)
  1184. {
  1185. QemuConsole *con;
  1186. QTAILQ_FOREACH(con, &consoles, next) {
  1187. QemuGraphicConsole *candidate;
  1188. if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
  1189. continue;
  1190. }
  1191. candidate = QEMU_GRAPHIC_CONSOLE(con);
  1192. if (candidate->device != c->device) {
  1193. continue;
  1194. }
  1195. if (candidate->head != c->head) {
  1196. return true;
  1197. }
  1198. }
  1199. return false;
  1200. }
  1201. char *qemu_console_get_label(QemuConsole *con)
  1202. {
  1203. if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
  1204. QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
  1205. if (c->device) {
  1206. DeviceState *dev;
  1207. bool multihead;
  1208. dev = DEVICE(c->device);
  1209. multihead = qemu_graphic_console_is_multihead(c);
  1210. if (multihead) {
  1211. return g_strdup_printf("%s.%d", dev->id ?
  1212. dev->id :
  1213. object_get_typename(c->device),
  1214. c->head);
  1215. } else {
  1216. return g_strdup_printf("%s", dev->id ?
  1217. dev->id :
  1218. object_get_typename(c->device));
  1219. }
  1220. }
  1221. return g_strdup("VGA");
  1222. } else if (QEMU_IS_TEXT_CONSOLE(con)) {
  1223. const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
  1224. if (label) {
  1225. return g_strdup(label);
  1226. }
  1227. }
  1228. return g_strdup_printf("vc%d", con->index);
  1229. }
  1230. int qemu_console_get_index(QemuConsole *con)
  1231. {
  1232. return con ? con->index : -1;
  1233. }
  1234. uint32_t qemu_console_get_head(QemuConsole *con)
  1235. {
  1236. if (con == NULL) {
  1237. return -1;
  1238. }
  1239. if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
  1240. return QEMU_GRAPHIC_CONSOLE(con)->head;
  1241. }
  1242. return 0;
  1243. }
  1244. int qemu_console_get_width(QemuConsole *con, int fallback)
  1245. {
  1246. if (con == NULL) {
  1247. return fallback;
  1248. }
  1249. switch (con->scanout.kind) {
  1250. case SCANOUT_DMABUF:
  1251. return qemu_dmabuf_get_width(con->scanout.dmabuf);
  1252. case SCANOUT_TEXTURE:
  1253. return con->scanout.texture.width;
  1254. case SCANOUT_SURFACE:
  1255. return surface_width(con->surface);
  1256. default:
  1257. return fallback;
  1258. }
  1259. }
  1260. int qemu_console_get_height(QemuConsole *con, int fallback)
  1261. {
  1262. if (con == NULL) {
  1263. return fallback;
  1264. }
  1265. switch (con->scanout.kind) {
  1266. case SCANOUT_DMABUF:
  1267. return qemu_dmabuf_get_height(con->scanout.dmabuf);
  1268. case SCANOUT_TEXTURE:
  1269. return con->scanout.texture.height;
  1270. case SCANOUT_SURFACE:
  1271. return surface_height(con->surface);
  1272. default:
  1273. return fallback;
  1274. }
  1275. }
  1276. int qemu_invalidate_text_consoles(void)
  1277. {
  1278. QemuConsole *s;
  1279. int count = 0;
  1280. QTAILQ_FOREACH(s, &consoles, next) {
  1281. if (qemu_console_is_graphic(s) ||
  1282. !qemu_console_is_visible(s)) {
  1283. continue;
  1284. }
  1285. count++;
  1286. graphic_hw_invalidate(s);
  1287. }
  1288. return count;
  1289. }
  1290. void qemu_console_resize(QemuConsole *s, int width, int height)
  1291. {
  1292. DisplaySurface *surface = qemu_console_surface(s);
  1293. assert(QEMU_IS_GRAPHIC_CONSOLE(s));
  1294. if ((s->scanout.kind != SCANOUT_SURFACE ||
  1295. (surface && surface_is_allocated(surface) &&
  1296. !surface_is_placeholder(surface))) &&
  1297. qemu_console_get_width(s, -1) == width &&
  1298. qemu_console_get_height(s, -1) == height) {
  1299. return;
  1300. }
  1301. surface = qemu_create_displaysurface(width, height);
  1302. dpy_gfx_replace_surface(s, surface);
  1303. }
  1304. DisplaySurface *qemu_console_surface(QemuConsole *console)
  1305. {
  1306. switch (console->scanout.kind) {
  1307. case SCANOUT_SURFACE:
  1308. return console->surface;
  1309. default:
  1310. return NULL;
  1311. }
  1312. }
  1313. PixelFormat qemu_default_pixelformat(int bpp)
  1314. {
  1315. pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
  1316. PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
  1317. return pf;
  1318. }
  1319. static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
  1320. void qemu_display_register(QemuDisplay *ui)
  1321. {
  1322. assert(ui->type < DISPLAY_TYPE__MAX);
  1323. dpys[ui->type] = ui;
  1324. }
  1325. bool qemu_display_find_default(DisplayOptions *opts)
  1326. {
  1327. static DisplayType prio[] = {
  1328. #if defined(CONFIG_GTK)
  1329. DISPLAY_TYPE_GTK,
  1330. #endif
  1331. #if defined(CONFIG_SDL)
  1332. DISPLAY_TYPE_SDL,
  1333. #endif
  1334. #if defined(CONFIG_COCOA)
  1335. DISPLAY_TYPE_COCOA
  1336. #endif
  1337. };
  1338. int i;
  1339. for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
  1340. if (dpys[prio[i]] == NULL) {
  1341. Error *local_err = NULL;
  1342. int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
  1343. if (rv < 0) {
  1344. error_report_err(local_err);
  1345. }
  1346. }
  1347. if (dpys[prio[i]] == NULL) {
  1348. continue;
  1349. }
  1350. opts->type = prio[i];
  1351. return true;
  1352. }
  1353. return false;
  1354. }
  1355. void qemu_display_early_init(DisplayOptions *opts)
  1356. {
  1357. assert(opts->type < DISPLAY_TYPE__MAX);
  1358. if (opts->type == DISPLAY_TYPE_NONE) {
  1359. return;
  1360. }
  1361. if (dpys[opts->type] == NULL) {
  1362. Error *local_err = NULL;
  1363. int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
  1364. if (rv < 0) {
  1365. error_report_err(local_err);
  1366. }
  1367. }
  1368. if (dpys[opts->type] == NULL) {
  1369. error_report("Display '%s' is not available.",
  1370. DisplayType_str(opts->type));
  1371. exit(1);
  1372. }
  1373. if (dpys[opts->type]->early_init) {
  1374. dpys[opts->type]->early_init(opts);
  1375. }
  1376. }
  1377. void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
  1378. {
  1379. assert(opts->type < DISPLAY_TYPE__MAX);
  1380. if (opts->type == DISPLAY_TYPE_NONE) {
  1381. return;
  1382. }
  1383. assert(dpys[opts->type] != NULL);
  1384. dpys[opts->type]->init(ds, opts);
  1385. }
  1386. const char *qemu_display_get_vc(DisplayOptions *opts)
  1387. {
  1388. #ifdef CONFIG_PIXMAN
  1389. const char *vc = "vc:80Cx24C";
  1390. #else
  1391. const char *vc = NULL;
  1392. #endif
  1393. assert(opts->type < DISPLAY_TYPE__MAX);
  1394. if (dpys[opts->type] && dpys[opts->type]->vc) {
  1395. vc = dpys[opts->type]->vc;
  1396. }
  1397. return vc;
  1398. }
  1399. void qemu_display_help(void)
  1400. {
  1401. int idx;
  1402. printf("Available display backend types:\n");
  1403. printf("none\n");
  1404. for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
  1405. if (!dpys[idx]) {
  1406. Error *local_err = NULL;
  1407. int rv = ui_module_load(DisplayType_str(idx), &local_err);
  1408. if (rv < 0) {
  1409. error_report_err(local_err);
  1410. }
  1411. }
  1412. if (dpys[idx]) {
  1413. printf("%s\n", DisplayType_str(dpys[idx]->type));
  1414. }
  1415. }
  1416. printf("\n"
  1417. "Some display backends support suboptions, which can be set with\n"
  1418. " -display backend,option=value,option=value...\n"
  1419. "For a short list of the suboptions for each display, see the "
  1420. "top-level -help output; more detail is in the documentation.\n");
  1421. }