1 /*
2 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
3 * TTTTTTTTTTTTTT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
4 * TT EE OO OO
5 * TT EE OO OO
6 * TT EE OO OO
7 * TT EEEEEEEEEE OO OO
8 * TT EEEEEEEEEE OO OO
9 * TT EE OO OO
10 * TT EE OO OO
11 * TT EE OO OO
12 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
13 * TT EEEEEEEEEEEEEE OOOOOOOOOOOOOO
14 *
15 * L'�mulateur Thomson TO8
16 *
17 * Copyright (C) 1997-2017 Gilles F�tis, Eric Botcazou, Alexandre Pukall,
18 * J�r�mie Guillaume, Fran�ois Mouret
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 */
34
35 /*
36 * Module : linux/udisplay.c
37 * Version : 1.8.4
38 * Cr�� par : Eric Botcazou octobre 1999
39 * Modifi� par: Eric Botcazou 24/11/2003
40 * Fran�ois Mouret 26/01/2010 08/2011 02/06/2012 28/12/2012
41 * 23/08/2015 31/07/2016
42 * Gilles F�tis 07/2011
43 *
44 * Module d'interface avec le serveur X.
45 */
46
47
48 #ifndef SCAN_DEPEND
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <gtk/gtk.h>
52 #include <gtk/gtkx.h>
53 #include <gdk/gdkx.h>
54 #include <X11/Xlib.h>
55 #include <X11/XKBlib.h>
56 #include <X11/Xutil.h>
57 #include <X11/keysym.h>
58 #endif
59
60 #include "defs.h"
61 #include "teo.h"
62 #include "to8keys.h"
63 #include "media/keyboard.h"
64 #include "media/mouse.h"
65 #include "media/disk.h"
66 #include "linux/gui.h"
67 #include "linux/display.h"
68 #include "linux/graphic.h"
69
70
71 GtkWidget *wMain;
72 GdkWindow *gwindow_win;
73 Display *display;
74 int screen;
75 int mit_shm_enabled;
76 Window screen_win;
77 Window window_win;
78
79 static int need_modifiers_reset = TRUE;
80
81 static int installed_pointer = TEO_STATUS_MOUSE;
82
83 static int x11_to_dos[256];
84
85 #define KB_SIZE 101
86 static struct {
87 int keysym;
88 int keycode;
89 } keyconv[KB_SIZE]={
90 { XK_Escape , TEO_KEY_ESC },
91 { XK_1 , TEO_KEY_1 },
92 { XK_2 , TEO_KEY_2 },
93 { XK_3 , TEO_KEY_3 },
94 { XK_4 , TEO_KEY_4 },
95 { XK_5 , TEO_KEY_5 },
96 { XK_6 , TEO_KEY_6 },
97 { XK_7 , TEO_KEY_7 },
98 { XK_8 , TEO_KEY_8 },
99 { XK_9 , TEO_KEY_9 },
100 { XK_0 , TEO_KEY_0 },
101 { XK_parenright , TEO_KEY_MINUS },
102 { XK_equal , TEO_KEY_EQUALS },
103 { XK_BackSpace , TEO_KEY_BACKSPACE },
104 { XK_Tab , TEO_KEY_TAB },
105 { XK_A , TEO_KEY_Q },
106 { XK_Z , TEO_KEY_W },
107 { XK_E , TEO_KEY_E },
108 { XK_R , TEO_KEY_R },
109 { XK_T , TEO_KEY_T },
110 { XK_Y , TEO_KEY_Y },
111 { XK_U , TEO_KEY_U },
112 { XK_I , TEO_KEY_I },
113 { XK_O , TEO_KEY_O },
114 { XK_P , TEO_KEY_P },
115 { XK_dead_circumflex , TEO_KEY_OPENBRACE },
116 { XK_dollar , TEO_KEY_CLOSEBRACE },
117 { XK_Return , TEO_KEY_ENTER },
118 { XK_Control_L , TEO_KEY_LCONTROL },
119 { XK_Q , TEO_KEY_A },
120 { XK_S , TEO_KEY_S },
121 { XK_D , TEO_KEY_D },
122 { XK_F , TEO_KEY_F },
123 { XK_G , TEO_KEY_G },
124 { XK_H , TEO_KEY_H },
125 { XK_J , TEO_KEY_J },
126 { XK_K , TEO_KEY_K },
127 { XK_L , TEO_KEY_L },
128 { XK_M , TEO_KEY_COLON },
129 { XK_percent , TEO_KEY_QUOTE },
130 { XK_twosuperior , TEO_KEY_TILDE },
131 { XK_Shift_L , TEO_KEY_LSHIFT },
132 { XK_asterisk , TEO_KEY_ASTERISK },
133 { XK_W , TEO_KEY_Z },
134 { XK_X , TEO_KEY_X },
135 { XK_C , TEO_KEY_C },
136 { XK_V , TEO_KEY_V },
137 { XK_B , TEO_KEY_B },
138 { XK_N , TEO_KEY_N },
139 { XK_comma , TEO_KEY_M },
140 { XK_semicolon , TEO_KEY_COMMA },
141 { XK_colon , TEO_KEY_STOP },
142 { XK_exclam , TEO_KEY_SLASH },
143 { XK_Shift_R , TEO_KEY_RSHIFT },
144 { XK_KP_Multiply , TEO_KEY_ASTERISK },
145 { XK_Alt_L , TEO_KEY_ALT },
146 { XK_space , TEO_KEY_SPACE },
147 { XK_Caps_Lock , TEO_KEY_CAPSLOCK },
148 { XK_F1 , TEO_KEY_F1 },
149 { XK_F2 , TEO_KEY_F2 },
150 { XK_F3 , TEO_KEY_F3 },
151 { XK_F4 , TEO_KEY_F4 },
152 { XK_F5 , TEO_KEY_F5 },
153 { XK_F6 , TEO_KEY_F6 },
154 { XK_F7 , TEO_KEY_F7 },
155 { XK_F8 , TEO_KEY_F8 },
156 { XK_F9 , TEO_KEY_F9 },
157 { XK_F10 , TEO_KEY_F10 },
158 { XK_Num_Lock , TEO_KEY_NUMLOCK },
159 { XK_Scroll_Lock , TEO_KEY_SCRLOCK },
160 { XK_KP_7 , TEO_KEY_7_PAD },
161 { XK_KP_8 , TEO_KEY_8_PAD },
162 { XK_KP_9 , TEO_KEY_9_PAD },
163 { XK_KP_Subtract , TEO_KEY_MINUS_PAD },
164 { XK_KP_4 , TEO_KEY_4_PAD },
165 { XK_KP_5 , TEO_KEY_5_PAD },
166 { XK_KP_6 , TEO_KEY_6_PAD },
167 { XK_KP_Add , TEO_KEY_PLUS_PAD },
168 { XK_KP_1 , TEO_KEY_1_PAD },
169 { XK_KP_2 , TEO_KEY_2_PAD },
170 { XK_KP_3 , TEO_KEY_3_PAD },
171 { XK_KP_0 , TEO_KEY_0_PAD },
172 { XK_KP_Decimal , TEO_KEY_DEL_PAD },
173 { XK_less , TEO_KEY_BACKSLASH2 },
174 { XK_F11 , TEO_KEY_F11 },
175 { XK_F12 , TEO_KEY_F12 },
176 { XK_KP_Enter , TEO_KEY_ENTER_PAD },
177 { XK_Control_R , TEO_KEY_RCONTROL },
178 { XK_KP_Divide , TEO_KEY_SLASH_PAD },
179 { XK_ISO_Level3_Shift, TEO_KEY_ALTGR },
180 { XK_Home , TEO_KEY_HOME },
181 { XK_Up , TEO_KEY_UP },
182 { XK_Page_Up , TEO_KEY_PGUP },
183 { XK_Left , TEO_KEY_LEFT },
184 { XK_Right , TEO_KEY_RIGHT },
185 { XK_End , TEO_KEY_END },
186 { XK_Down , TEO_KEY_DOWN },
187 { XK_Page_Down , TEO_KEY_PGDN },
188 { XK_Insert , TEO_KEY_INSERT },
189 { XK_Delete , TEO_KEY_DEL }
190 };
191
192
193
194 /* SetPointer:
195 * S�lectionne le pointeur actif.
196 */
SetPointer(int pointer)197 static void SetPointer(int pointer)
198 {
199 switch (pointer)
200 {
201 case TEO_STATUS_MOUSE :
202 gdk_window_set_cursor (gwindow_win, NULL);
203 installed_pointer=TEO_STATUS_MOUSE;
204 break;
205
206 case TEO_STATUS_LIGHTPEN :
207 gdk_window_set_cursor (gwindow_win, gdk_cursor_new_for_display (gdk_window_get_display (gwindow_win), GDK_PENCIL));
208 installed_pointer=TEO_STATUS_LIGHTPEN;
209 break;
210 }
211 }
212
213
214 /* button_release_event:
215 * Gestion des touches enfonc�es.
216 */
217 static gboolean
delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)218 delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
219 {
220 teo.command = TEO_COMMAND_QUIT;
221
222 return TRUE;
223 (void)widget;
224 (void)event;
225 (void)user_data;
226 }
227
228
229 /* key_press_event:
230 * Gestion des touches enfonc�es.
231 */
232 static gboolean
key_press_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)233 key_press_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
234 {
235 int value = 0;
236 int teo_key = 0;
237
238 if (need_modifiers_reset)
239 {
240 if (event->key.state & GDK_SHIFT_MASK) value |= TEO_KEY_F_SHIFT;
241 if (event->key.state & GDK_CONTROL_MASK) value |= TEO_KEY_F_CTRL;
242 if (event->key.state & GDK_MOD3_MASK) value |= TEO_KEY_F_ALTGR;
243 if (event->key.state & GDK_MOD2_MASK) value |= TEO_KEY_F_NUMLOCK;
244 if (event->key.state & GDK_LOCK_MASK) value |= TEO_KEY_F_CAPSLOCK;
245 keyboard_Reset ((1<<TEO_KEY_F_MAX)-1, value);
246 need_modifiers_reset = FALSE;
247 }
248
249 teo_key = x11_to_dos[event->key.hardware_keycode];
250 if (teo_key == 0)
251 {
252 if (event->key.keyval == GDK_KEY_ISO_Level3_Shift)
253 teo_key = TEO_KEY_ALTGR;
254
255 /* Convert delete keypad key to point character
256 * Over the time, Linux keypad delete key raw code has changed from
257 * GDK_KEY_KP_Delete to GDK_KEY_KP_Decimal and case GDK_KEY_period,
258 * so the ASCII corresponding value is now checked directly
259 * with the 0x2e value.
260 */
261 if (event->key.keyval == 0x2e)
262 teo_key = TEO_KEY_DEL_PAD;
263 }
264
265 switch (teo_key)
266 {
267 case TEO_KEY_ESC : teo.command=TEO_COMMAND_PANEL; break;
268 case TEO_KEY_F12 : teo.command=TEO_COMMAND_DEBUGGER; break;
269 default : keyboard_Press (teo_key, FALSE); break;
270 }
271 return FALSE;
272 (void)widget;
273 (void)user_data;
274 }
275
276
277 /* key_release_event:
278 * Gestion des touches relach�es.
279 */
280 static gboolean
key_release_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)281 key_release_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
282 {
283 int teo_key = x11_to_dos[event->key.hardware_keycode];
284
285 if (teo_key == 0)
286 if (event->key.keyval == GDK_KEY_ISO_Level3_Shift)
287 teo_key = TEO_KEY_ALTGR;
288
289 keyboard_Press (teo_key, TRUE);
290 return FALSE;
291 (void)widget;
292 (void)user_data;
293 }
294
295
296 /* button_press_event:
297 * Gestion des boutons de souris enfonc�s.
298 */
299 static gboolean
button_press_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)300 button_press_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
301 {
302 switch (event->button.button)
303 {
304 case 1 : mouse_Click(1, FALSE); break;
305 case 3 : if (installed_pointer == TEO_STATUS_MOUSE)
306 mouse_Click (2, FALSE);
307 break;
308 }
309 return FALSE;
310 (void)widget;
311 (void)user_data;
312 }
313
314
315 /* button_release_event:
316 * Gestion des boutons de souris relach�s.
317 */
318 static gboolean
button_release_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)319 button_release_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
320 {
321 switch (event->button.button)
322 {
323 case 1 : mouse_Click (1, TRUE); break;
324 case 3 : mouse_Click (2, TRUE); break;
325 }
326 return FALSE;
327 (void)widget;
328 (void)user_data;
329 }
330
331
332 /* motion_notify_event:
333 * Gestion des mouvements de la souris.
334 */
335 static gboolean
motion_notify_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)336 motion_notify_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
337 {
338 if (((int)event->button.x > (TEO_BORDER_W*2))
339 && ((int)event->button.y > (TEO_BORDER_H*2)))
340 mouse_Motion ((int)event->button.x/2-TEO_BORDER_W,
341 (int)event->button.y/2-TEO_BORDER_H);
342 gdk_event_request_motions ((GdkEventMotion *) event);
343 return FALSE;
344 (void)widget;
345 (void)user_data;
346 }
347
348
349 /* focus_in_event:
350 * Gestion des activations de fen�tres.
351 */
352 static gboolean
focus_in_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)353 focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
354 {
355 if (event->focus_change.in == TRUE)
356 {
357 keyboard_Reset (0, 0);
358 need_modifiers_reset = TRUE;
359 }
360 return FALSE;
361 (void)widget;
362 (void)user_data;
363 }
364
365
366 /* visibility_notify_event:
367 * Gestion du retra�age de l'�cran.
368 */
369 static gboolean
visibility_notify_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)370 visibility_notify_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
371 {
372 if (event->visibility.state == GDK_VISIBILITY_UNOBSCURED)
373 ugraphic_Retrace(0, 0, TEO_SCREEN_W*2, TEO_SCREEN_H*2);
374
375 return FALSE;
376 (void)widget;
377 (void)user_data;
378 }
379
380
381 /* ------------------------------------------------------------------------- */
382
383
384 /* udisplay_Init:
385 * Ouvre la connexion avec le serveur X et initialise le clavier.
386 */
udisplay_Init(void)387 void udisplay_Init(void)
388 {
389 int i;
390 int ret1, ret2, ret3;
391
392 /* Connexion au serveur X */
393 display=gdk_x11_get_default_xdisplay();
394 screen=DefaultScreen(display);
395
396 /* Calcul de la table de conversion des keycodes */
397 for (i=0; i<KB_SIZE; i++)
398 x11_to_dos[XKeysymToKeycode(display,keyconv[i].keysym)]=keyconv[i].keycode;
399
400 /* Test de pr�sence de l'extension MIT-SHM */
401 mit_shm_enabled = XQueryExtension(display, "MIT-SHM", &ret1, &ret2, &ret3);
402 }
403
404
405
406 /* udisplay_Window:
407 * Cr�e la fen�tre principale.
408 */
udisplay_Window(void)409 void udisplay_Window(void)
410 {
411 GdkPixbuf *pixbuf;
412 GdkGeometry hints;
413 GtkCssProvider *provider;
414 GtkStyleContext *context;
415
416 wMain = gtk_window_new (GTK_WINDOW_TOPLEVEL);
417
418 gtk_window_set_resizable (GTK_WINDOW(wMain), FALSE);
419 gtk_window_set_title (GTK_WINDOW(wMain),
420 is_fr?"Teo - l'émulateur TO8 (menu:ESC/débogueur:F12)"
421 :"Teo - thomson TO8 emulator (menu:ESC/debugger:F12)");
422
423 gtk_widget_add_events (wMain,
424 GDK_FOCUS_CHANGE_MASK
425 | GDK_VISIBILITY_NOTIFY_MASK
426 | GDK_KEY_RELEASE_MASK
427 | GDK_KEY_PRESS_MASK
428 | GDK_STRUCTURE_MASK
429 | GDK_BUTTON_RELEASE_MASK
430 | GDK_BUTTON_PRESS_MASK
431 | GDK_POINTER_MOTION_MASK);
432
433 g_signal_connect (G_OBJECT (wMain), "delete-event",
434 G_CALLBACK (delete_event), NULL);
435 g_signal_connect (G_OBJECT (wMain), "key-press-event",
436 G_CALLBACK (key_press_event), NULL);
437 g_signal_connect (G_OBJECT (wMain), "key-release-event",
438 G_CALLBACK (key_release_event), NULL);
439 g_signal_connect (G_OBJECT (wMain), "button-press-event",
440 G_CALLBACK (button_press_event), NULL);
441 g_signal_connect (G_OBJECT (wMain), "button-release-event",
442 G_CALLBACK (button_release_event), NULL);
443 g_signal_connect (G_OBJECT (wMain), "motion-notify-event",
444 G_CALLBACK (motion_notify_event), NULL);
445 g_signal_connect (G_OBJECT (wMain), "focus-in-event",
446 G_CALLBACK (focus_in_event), NULL);
447 g_signal_connect (G_OBJECT (wMain), "visibility-notify-event",
448 G_CALLBACK (visibility_notify_event), NULL);
449
450 /* Set window size */
451 hints.min_width = TEO_SCREEN_W*2;
452 hints.max_width = TEO_SCREEN_W*2;
453 hints.min_height = TEO_SCREEN_H*2;
454 hints.max_height = TEO_SCREEN_H*2;
455 gtk_window_set_geometry_hints (GTK_WINDOW(wMain), wMain, &hints,
456 GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
457
458 /* Move the window */
459 gtk_window_move (GTK_WINDOW(wMain), 0, 0);
460
461 /* Set program icon */
462 pixbuf=gdk_pixbuf_new_from_resource("/net/sourceforge/teoemulator/teo.png", NULL);
463 gtk_window_set_icon (GTK_WINDOW(wMain),pixbuf);
464 gtk_window_set_default_icon(pixbuf);
465
466 /* Set black background */
467 provider = gtk_css_provider_new ();
468 gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (provider),
469 "* { background-color: #000000; }",
470 -1, NULL);
471 context = gtk_widget_get_style_context (wMain);
472 gtk_style_context_add_provider (context,
473 GTK_STYLE_PROVIDER (provider),
474 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
475 g_object_unref (provider);
476
477 gtk_widget_set_double_buffered (wMain, FALSE); /* only one buffer for drawing */
478 gtk_widget_set_app_paintable (wMain, TRUE);
479 gtk_widget_set_can_focus (wMain, TRUE);
480
481 gtk_widget_show_all (wMain);
482
483 gwindow_win = gtk_widget_get_window (wMain);
484
485 #ifndef SCAN_DEPEND
486 #if GTK_CHECK_VERSION(3,12,0)
487 gdk_window_set_event_compression (gwindow_win, FALSE);
488 #endif
489 #endif
490 window_win = GDK_WINDOW_XID (gwindow_win);
491 screen_win = window_win;
492
493 teo_SetPointer=SetPointer;
494
495 printf("ok\n");
496 }
497
498