1 /* Public Domain Curses */
5 RCSID("$Id: x11.c,v 1.94 2008/07/14 04:33:26 wmcbrine Exp $")
7 #ifdef HAVE_DECKEYSYM_H
8 # include <DECkeysym.h>
11 #ifdef HAVE_SUNKEYSYM_H
12 # include <Sunkeysym.h>
26 #ifndef XPOINTER_TYPEDEFED
27 typedef char * XPointer
;
34 XCursesAppData xc_app_data
;
36 #if NeedWidePrototypes
37 # define PDC_SCROLLBAR_TYPE double
39 # define PDC_SCROLLBAR_TYPE float
42 #define MAX_COLORS 16 /* maximum of "normal" colors */
43 #define COLOR_CURSOR MAX_COLORS /* color of cursor */
44 #define COLOR_BORDER MAX_COLORS + 1 /* color of border */
46 #define XCURSESDISPLAY (XtDisplay(drawing))
47 #define XCURSESWIN (XtWindow(drawing))
49 /* Default icons for XCurses applications. */
51 #include "big_icon.xbm"
52 #include "little_icon.xbm"
54 static void _selection_off(void);
55 static void _display_cursor(int, int, int, int);
56 static void _redraw_cursor(void);
57 static void _exit_process(int, int, char *);
58 static void _send_key_to_curses(unsigned long, MOUSE_STATUS
*, bool);
60 static void XCursesButton(Widget
, XEvent
*, String
*, Cardinal
*);
61 static void XCursesHandleString(Widget
, XEvent
*, String
*, Cardinal
*);
62 static void XCursesKeyPress(Widget
, XEvent
*, String
*, Cardinal
*);
63 static void XCursesPasteSelection(Widget
, XButtonEvent
*);
69 unsigned short normal
;
70 unsigned short shifted
;
71 unsigned short control
;
75 /* keycode keypad normal shifted control alt*/
76 {XK_Left
, FALSE
, KEY_LEFT
, KEY_SLEFT
, CTL_LEFT
, ALT_LEFT
},
77 {XK_Right
, FALSE
, KEY_RIGHT
, KEY_SRIGHT
, CTL_RIGHT
, ALT_RIGHT
},
78 {XK_Up
, FALSE
, KEY_UP
, KEY_SUP
, CTL_UP
, ALT_UP
},
79 {XK_Down
, FALSE
, KEY_DOWN
, KEY_SDOWN
, CTL_DOWN
, ALT_DOWN
},
80 {XK_Home
, FALSE
, KEY_HOME
, KEY_SHOME
, CTL_HOME
, ALT_HOME
},
81 /* Sun Type 4 keyboard */
82 {XK_R7
, FALSE
, KEY_HOME
, KEY_SHOME
, CTL_HOME
, ALT_HOME
},
83 {XK_End
, FALSE
, KEY_END
, KEY_SEND
, CTL_END
, ALT_END
},
84 /* Sun Type 4 keyboard */
85 {XK_R13
, FALSE
, KEY_END
, KEY_SEND
, CTL_END
, ALT_END
},
86 {XK_Prior
, FALSE
, KEY_PPAGE
, KEY_SPREVIOUS
,CTL_PGUP
, ALT_PGUP
},
87 /* Sun Type 4 keyboard */
88 {XK_R9
, FALSE
, KEY_PPAGE
, KEY_SPREVIOUS
,CTL_PGUP
, ALT_PGUP
},
89 {XK_Next
, FALSE
, KEY_NPAGE
, KEY_SNEXT
, CTL_PGDN
, ALT_PGDN
},
90 /* Sun Type 4 keyboard */
91 {XK_R15
, FALSE
, KEY_NPAGE
, KEY_SNEXT
, CTL_PGDN
, ALT_PGDN
},
92 {XK_Insert
, FALSE
, KEY_IC
, KEY_SIC
, CTL_INS
, ALT_INS
},
93 {XK_Delete
, FALSE
, KEY_DC
, KEY_SDC
, CTL_DEL
, ALT_DEL
},
94 {XK_F1
, FALSE
, KEY_F(1), KEY_F(13), KEY_F(25), KEY_F(37)},
95 {XK_F2
, FALSE
, KEY_F(2), KEY_F(14), KEY_F(26), KEY_F(38)},
96 {XK_F3
, FALSE
, KEY_F(3), KEY_F(15), KEY_F(27), KEY_F(39)},
97 {XK_F4
, FALSE
, KEY_F(4), KEY_F(16), KEY_F(28), KEY_F(40)},
98 {XK_F5
, FALSE
, KEY_F(5), KEY_F(17), KEY_F(29), KEY_F(41)},
99 {XK_F6
, FALSE
, KEY_F(6), KEY_F(18), KEY_F(30), KEY_F(42)},
100 {XK_F7
, FALSE
, KEY_F(7), KEY_F(19), KEY_F(31), KEY_F(43)},
101 {XK_F8
, FALSE
, KEY_F(8), KEY_F(20), KEY_F(32), KEY_F(44)},
102 {XK_F9
, FALSE
, KEY_F(9), KEY_F(21), KEY_F(33), KEY_F(45)},
103 {XK_F10
, FALSE
, KEY_F(10), KEY_F(22), KEY_F(34), KEY_F(46)},
104 {XK_F11
, FALSE
, KEY_F(11), KEY_F(23), KEY_F(35), KEY_F(47)},
105 {XK_F12
, FALSE
, KEY_F(12), KEY_F(24), KEY_F(36), KEY_F(48)},
106 {XK_F13
, FALSE
, KEY_F(13), KEY_F(25), KEY_F(37), KEY_F(49)},
107 {XK_F14
, FALSE
, KEY_F(14), KEY_F(26), KEY_F(38), KEY_F(50)},
108 {XK_F15
, FALSE
, KEY_F(15), KEY_F(27), KEY_F(39), KEY_F(51)},
109 {XK_F16
, FALSE
, KEY_F(16), KEY_F(28), KEY_F(40), KEY_F(52)},
110 {XK_F17
, FALSE
, KEY_F(17), KEY_F(29), KEY_F(41), KEY_F(53)},
111 {XK_F18
, FALSE
, KEY_F(18), KEY_F(30), KEY_F(42), KEY_F(54)},
112 {XK_F19
, FALSE
, KEY_F(19), KEY_F(31), KEY_F(43), KEY_F(55)},
113 {XK_F20
, FALSE
, KEY_F(20), KEY_F(32), KEY_F(44), KEY_F(56)},
114 {XK_BackSpace
, FALSE
, 0x08, 0x08, CTL_BKSP
, ALT_BKSP
},
115 {XK_Tab
, FALSE
, 0x09, KEY_BTAB
, CTL_TAB
, ALT_TAB
},
116 {XK_Select
, FALSE
, KEY_SELECT
, KEY_SELECT
, KEY_SELECT
, KEY_SELECT
},
117 {XK_Print
, FALSE
, KEY_PRINT
, KEY_SPRINT
, KEY_PRINT
, KEY_PRINT
},
118 {XK_Find
, FALSE
, KEY_FIND
, KEY_SFIND
, KEY_FIND
, KEY_FIND
},
119 {XK_Pause
, FALSE
, KEY_SUSPEND
, KEY_SSUSPEND
, KEY_SUSPEND
, KEY_SUSPEND
},
120 {XK_Clear
, FALSE
, KEY_CLEAR
, KEY_CLEAR
, KEY_CLEAR
, KEY_CLEAR
},
121 {XK_Cancel
, FALSE
, KEY_CANCEL
, KEY_SCANCEL
, KEY_CANCEL
, KEY_CANCEL
},
122 {XK_Break
, FALSE
, KEY_BREAK
, KEY_BREAK
, KEY_BREAK
, KEY_BREAK
},
123 {XK_Help
, FALSE
, KEY_HELP
, KEY_SHELP
, KEY_LHELP
, KEY_HELP
},
124 {XK_L4
, FALSE
, KEY_UNDO
, KEY_SUNDO
, KEY_UNDO
, KEY_UNDO
},
125 {XK_L6
, FALSE
, KEY_COPY
, KEY_SCOPY
, KEY_COPY
, KEY_COPY
},
126 {XK_L9
, FALSE
, KEY_FIND
, KEY_SFIND
, KEY_FIND
, KEY_FIND
},
127 {XK_Menu
, FALSE
, KEY_OPTIONS
, KEY_SOPTIONS
, KEY_OPTIONS
, KEY_OPTIONS
},
128 #ifdef HAVE_SUNKEYSYM_H
129 {SunXK_F36
, FALSE
, KEY_F(41), KEY_F(43), KEY_F(45), KEY_F(47)},
130 {SunXK_F37
, FALSE
, KEY_F(42), KEY_F(44), KEY_F(46), KEY_F(48)},
132 #ifdef HAVE_DECKEYSYM_H
133 {DXK_Remove
, FALSE
, KEY_DC
, KEY_SDC
, CTL_DEL
, ALT_DEL
},
135 {XK_Escape
, FALSE
, 0x1B, 0x1B, 0x1B, ALT_ESC
},
136 {XK_KP_Enter
, TRUE
, PADENTER
, PADENTER
, CTL_PADENTER
,ALT_PADENTER
},
137 {XK_KP_Add
, TRUE
, PADPLUS
, '+', CTL_PADPLUS
, ALT_PADPLUS
},
138 {XK_KP_Subtract
,TRUE
, PADMINUS
, '-', CTL_PADMINUS
,ALT_PADMINUS
},
139 {XK_KP_Multiply
,TRUE
, PADSTAR
, '*', CTL_PADSTAR
, ALT_PADSTAR
},
140 /* Sun Type 4 keyboard */
141 {XK_R6
, TRUE
, PADSTAR
, '*', CTL_PADSTAR
, ALT_PADSTAR
},
142 {XK_KP_Divide
, TRUE
, PADSLASH
, '/', CTL_PADSLASH
,ALT_PADSLASH
},
143 /* Sun Type 4 keyboard */
144 {XK_R5
, TRUE
, PADSLASH
, '/', CTL_PADSLASH
,ALT_PADSLASH
},
145 {XK_KP_Decimal
,TRUE
, PADSTOP
, '.', CTL_PADSTOP
, ALT_PADSTOP
},
146 {XK_KP_0
, TRUE
, PAD0
, '0', CTL_PAD0
, ALT_PAD0
},
147 {XK_KP_1
, TRUE
, KEY_C1
, '1', CTL_PAD1
, ALT_PAD1
},
148 {XK_KP_2
, TRUE
, KEY_C2
, '2', CTL_PAD2
, ALT_PAD2
},
149 {XK_KP_3
, TRUE
, KEY_C3
, '3', CTL_PAD3
, ALT_PAD3
},
150 {XK_KP_4
, TRUE
, KEY_B1
, '4', CTL_PAD4
, ALT_PAD4
},
151 {XK_KP_5
, TRUE
, KEY_B2
, '5', CTL_PAD5
, ALT_PAD5
},
152 /* Sun Type 4 keyboard */
153 {XK_R11
, TRUE
, KEY_B2
, '5', CTL_PAD5
, ALT_PAD5
},
154 {XK_KP_6
, TRUE
, KEY_B3
, '6', CTL_PAD6
, ALT_PAD6
},
155 {XK_KP_7
, TRUE
, KEY_A1
, '7', CTL_PAD7
, ALT_PAD7
},
156 {XK_KP_8
, TRUE
, KEY_A2
, '8', CTL_PAD8
, ALT_PAD8
},
157 {XK_KP_9
, TRUE
, KEY_A3
, '9', CTL_PAD9
, ALT_PAD9
},
158 /* the following added to support Sun Type 5 keyboards */
159 {XK_F21
, FALSE
, KEY_SUSPEND
, KEY_SSUSPEND
, KEY_SUSPEND
, KEY_SUSPEND
},
160 {XK_F22
, FALSE
, KEY_PRINT
, KEY_SPRINT
, KEY_PRINT
, KEY_PRINT
},
161 {XK_F24
, TRUE
, PADMINUS
, '-', CTL_PADMINUS
,ALT_PADMINUS
},
162 /* Sun Type 4 keyboard */
163 {XK_F25
, TRUE
, PADSLASH
, '/', CTL_PADSLASH
,ALT_PADSLASH
},
164 /* Sun Type 4 keyboard */
165 {XK_F26
, TRUE
, PADSTAR
, '*', CTL_PADSTAR
, ALT_PADSTAR
},
166 {XK_F27
, TRUE
, KEY_A1
, '7', CTL_PAD7
, ALT_PAD7
},
167 {XK_F29
, TRUE
, KEY_A3
, '9', CTL_PAD9
, ALT_PAD9
},
168 {XK_F31
, TRUE
, KEY_B2
, '5', CTL_PAD5
, ALT_PAD5
},
169 {XK_F35
, TRUE
, KEY_C3
, '3', CTL_PAD3
, ALT_PAD3
},
170 #ifdef HAVE_XK_KP_DELETE
171 {XK_KP_Delete
, TRUE
, PADSTOP
, '.', CTL_PADSTOP
, ALT_PADSTOP
},
173 #ifdef HAVE_XK_KP_INSERT
174 {XK_KP_Insert
, TRUE
, PAD0
, '0', CTL_PAD0
, ALT_PAD0
},
176 #ifdef HAVE_XK_KP_END
177 {XK_KP_End
, TRUE
, KEY_C1
, '1', CTL_PAD1
, ALT_PAD1
},
179 #ifdef HAVE_XK_KP_DOWN
180 {XK_KP_Down
, TRUE
, KEY_C2
, '2', CTL_PAD2
, ALT_PAD2
},
182 #ifdef HAVE_XK_KP_NEXT
183 {XK_KP_Next
, TRUE
, KEY_C3
, '3', CTL_PAD3
, ALT_PAD3
},
185 #ifdef HAVE_XK_KP_LEFT
186 {XK_KP_Left
, TRUE
, KEY_B1
, '4', CTL_PAD4
, ALT_PAD4
},
188 #ifdef HAVE_XK_KP_BEGIN
189 {XK_KP_Begin
, TRUE
, KEY_B2
, '5', CTL_PAD5
, ALT_PAD5
},
191 #ifdef HAVE_XK_KP_RIGHT
192 {XK_KP_Right
, TRUE
, KEY_B3
, '6', CTL_PAD6
, ALT_PAD6
},
194 #ifdef HAVE_XK_KP_HOME
195 {XK_KP_Home
, TRUE
, KEY_A1
, '7', CTL_PAD7
, ALT_PAD7
},
198 {XK_KP_Up
, TRUE
, KEY_A2
, '8', CTL_PAD8
, ALT_PAD8
},
200 #ifdef HAVE_XK_KP_PRIOR
201 {XK_KP_Prior
, TRUE
, KEY_A3
, '9', CTL_PAD9
, ALT_PAD9
},
207 # include "compose.h"
210 #define BITMAPDEPTH 1
212 unsigned long pdc_key_modifiers
= 0L;
214 static GC normal_gc
, block_cursor_gc
, rect_cursor_gc
, italic_gc
, border_gc
;
215 static int font_height
, font_width
, font_ascent
, font_descent
,
216 window_width
, window_height
;
217 static int resize_window_width
= 0, resize_window_height
= 0;
218 static char *bitmap_file
= NULL
;
220 static char *pixmap_file
= NULL
;
222 static KeySym keysym
= 0;
224 static int state_mask
[8] =
236 static Atom wm_atom
[2];
237 static String class_name
= "XCurses";
238 static XtAppContext app_context
;
239 static Widget topLevel
, drawing
, scrollBox
, scrollVert
, scrollHoriz
;
240 static int received_map_notify
= 0;
241 static bool mouse_selection
= FALSE
;
242 static chtype
*tmpsel
= NULL
;
243 static unsigned long tmpsel_length
= 0;
244 static int selection_start_x
= 0, selection_start_y
= 0,
245 selection_end_x
= 0, selection_end_y
= 0;
246 static Pixmap icon_bitmap
;
248 static Pixmap icon_pixmap
;
249 static Pixmap icon_pixmap_mask
;
251 static bool visible_cursor
= FALSE
;
252 static bool window_entered
= TRUE
;
253 static char *program_name
;
255 /* Macros just for app_resources */
258 # define DEFFONT "-misc-fixed-medium-r-normal--20-200-75-75-c-100-iso10646-1"
260 # define DEFFONT "7x13"
263 #define APPDATAOFF(n) XtOffsetOf(XCursesAppData, n)
265 #define RINT(name1, name2, value) { \
266 #name1, #name2, XtRInt, \
267 sizeof(int), APPDATAOFF(name1), XtRImmediate, \
271 #define RPIXEL(name1, name2, value) { \
272 #name1, #name2, XtRPixel, \
273 sizeof(Pixel), APPDATAOFF(name1), XtRString, \
277 #define RCOLOR(name, value) RPIXEL(color##name, Color##name, value)
279 #define RSTRINGP(name1, name2, param) { \
280 #name1, #name2, XtRString, \
281 MAX_PATH, APPDATAOFF(name1), XtRString, (XtPointer)param \
284 #define RSTRING(name1, name2) RSTRINGP(name1, name2, "")
286 #define RFONT(name1, name2, value) { \
287 #name1, #name2, XtRFontStruct, \
288 sizeof(XFontStruct), APPDATAOFF(name1), XtRString, \
292 #define RCURSOR(name1, name2, value) { \
293 #name1, #name2, XtRCursor, \
294 sizeof(Cursor), APPDATAOFF(name1), XtRString, \
298 static XtResource app_resources
[] =
300 RINT(lines
, Lines
, 24),
301 RINT(cols
, Cols
, 80),
303 RPIXEL(cursorColor
, CursorColor
, Red
),
305 RCOLOR(Black
, Black
),
307 RCOLOR(Green
, green3
),
308 RCOLOR(Yellow
, yellow3
),
310 RCOLOR(Magenta
, magenta3
),
314 RCOLOR(BoldBlack
, grey40
),
315 RCOLOR(BoldRed
, red1
),
316 RCOLOR(BoldGreen
, green1
),
317 RCOLOR(BoldYellow
, yellow1
),
318 RCOLOR(BoldBlue
, blue1
),
319 RCOLOR(BoldMagenta
, magenta1
),
320 RCOLOR(BoldCyan
, cyan1
),
321 RCOLOR(BoldWhite
, White
),
323 RFONT(normalFont
, NormalFont
, DEFFONT
),
324 RFONT(italicFont
, ItalicFont
, DEFFONT
),
326 RSTRING(bitmap
, Bitmap
),
328 RSTRING(pixmap
, Pixmap
),
330 RSTRINGP(composeKey
, ComposeKey
, "Multi_key"),
332 RCURSOR(pointer
, Pointer
, xterm
),
334 RPIXEL(pointerForeColor
, PointerForeColor
, Black
),
335 RPIXEL(pointerBackColor
, PointerBackColor
, White
),
337 RINT(shmmin
, Shmmin
, 0),
338 RINT(borderWidth
, BorderWidth
, 0),
340 RPIXEL(borderColor
, BorderColor
, Black
),
342 RINT(doubleClickPeriod
, DoubleClickPeriod
, (PDC_CLICK_PERIOD
* 2)),
343 RINT(clickPeriod
, ClickPeriod
, PDC_CLICK_PERIOD
),
344 RINT(scrollbarWidth
, ScrollbarWidth
, 15),
345 RINT(cursorBlinkRate
, CursorBlinkRate
, 0),
347 RSTRING(textCursor
, TextCursor
)
359 /* Macros for options */
361 #define COPT(name) {"-" #name, "*" #name, XrmoptionSepArg, NULL}
362 #define CCOLOR(name) COPT(color##name)
364 static XrmOptionDescRec options
[] =
366 COPT(lines
), COPT(cols
), COPT(normalFont
), COPT(italicFont
),
371 COPT(pointer
), COPT(shmmin
), COPT(composeKey
), COPT(clickPeriod
),
372 COPT(doubleClickPeriod
), COPT(scrollbarWidth
),
373 COPT(pointerForeColor
), COPT(pointerBackColor
),
374 COPT(cursorBlinkRate
), COPT(cursorColor
), COPT(textCursor
),
376 CCOLOR(Black
), CCOLOR(Red
), CCOLOR(Green
), CCOLOR(Yellow
),
377 CCOLOR(Blue
), CCOLOR(Magenta
), CCOLOR(Cyan
), CCOLOR(White
),
379 CCOLOR(BoldBlack
), CCOLOR(BoldRed
), CCOLOR(BoldGreen
),
380 CCOLOR(BoldYellow
), CCOLOR(BoldBlue
), CCOLOR(BoldMagenta
),
381 CCOLOR(BoldCyan
), CCOLOR(BoldWhite
)
387 static XtActionsRec action_table
[] =
389 {"XCursesButton", (XtActionProc
)XCursesButton
},
390 {"XCursesKeyPress", (XtActionProc
)XCursesKeyPress
},
391 {"XCursesPasteSelection", (XtActionProc
)XCursesPasteSelection
},
392 {"string", (XtActionProc
)XCursesHandleString
}
395 static bool after_first_curses_request
= FALSE
;
396 static Pixel colors
[MAX_COLORS
+ 2];
397 static bool vertical_cursor
= FALSE
;
400 static XIM Xim
= NULL
;
401 static XIC Xic
= NULL
;
404 static const char *default_translations
=
406 "<Key>: XCursesKeyPress() \n" \
407 "<KeyUp>: XCursesKeyPress() \n" \
408 "<BtnDown>: XCursesButton() \n" \
409 "<BtnUp>: XCursesButton() \n" \
410 "<BtnMotion>: XCursesButton()"
413 static int _to_utf8(char *outcode
, chtype code
)
416 if (code
& A_ALTCHARSET
&& !(code
& 0xff80))
417 code
= acs_map
[code
& 0x7f];
429 outcode
[0] = ((code
& 0x07c0) >> 6) | 0xc0;
430 outcode
[1] = (code
& 0x003f) | 0x80;
435 outcode
[0] = ((code
& 0xf000) >> 12) | 0xe0;
436 outcode
[1] = ((code
& 0x0fc0) >> 6) | 0x80;
437 outcode
[2] = (code
& 0x003f) | 0x80;
442 static int _from_utf8(wchar_t *pwc
, const char *s
, size_t n
)
446 const unsigned char *string
;
454 string
= (const unsigned char *)s
;
458 /* Simplistic UTF-8 decoder -- only does the BMP, minimal validation */
462 if ((key
& 0xe0) == 0xc0)
466 key
= ((key
& 0x1f) << 6) | (string
[1] & 0x3f);
470 else if ((key
& 0xe0) == 0xe0)
474 key
= ((key
& 0x0f) << 12) |
475 ((string
[1] & 0x3f) << 6) | (string
[2] & 0x3f);
489 #ifndef X_HAVE_UTF8_STRING
490 static Atom
XA_UTF8_STRING(Display
*dpy
)
492 static AtomPtr p
= NULL
;
495 p
= XmuMakeAtom("UTF8_STRING");
497 return XmuInternAtom(dpy
, p
);
501 signal_handler
XCursesSetSignal(int signo
, signal_handler action
)
503 #if defined(SA_INTERRUPT) || defined(SA_RESTART)
504 struct sigaction sigact
, osigact
;
506 sigact
.sa_handler
= action
;
511 SA_INTERRUPT
| SA_RESTART
;
515 # else /* must be SA_RESTART */
518 sigemptyset(&sigact
.sa_mask
);
520 if (sigaction(signo
, &sigact
, &osigact
))
523 return osigact
.sa_handler
;
525 #else /* not SA_INTERRUPT or SA_RESTART, use plain signal */
526 return signal(signo
, action
);
530 RETSIGTYPE
XCursesSigwinchHandler(int signo
)
532 PDC_LOG(("%s:XCursesSigwinchHandler() - called: SIGNO: %d\n",
535 /* Patch by: Georg Fuchs, georg.fuchs@rz.uni-regensburg.de
540 /* Always trap SIGWINCH if the C library supports SIGWINCH */
543 XCursesSetSignal(SIGWINCH
, XCursesSigwinchHandler
);
547 /* Convert character positions x and y to pixel positions, stored in
550 static void _make_xy(int x
, int y
, int *xpos
, int *ypos
)
552 *xpos
= (x
* font_width
) + xc_app_data
.borderWidth
;
553 *ypos
= xc_app_data
.normalFont
->ascent
+ (y
* font_height
) +
554 xc_app_data
.borderWidth
;
557 /* Output a block of characters with common attributes */
559 static int _new_packet(chtype attr
, bool rev
, int len
, int col
, int row
,
570 PDC_pair_content(PAIR_NUMBER(attr
), &fore
, &back
);
573 text
[len
].byte1
= text
[len
].byte2
= 0;
578 /* Specify the color table offsets */
580 fore
|= (attr
& A_BOLD
) ? 8 : 0;
581 back
|= (attr
& A_BLINK
) ? 8 : 0;
583 /* Reverse flag = highlighted selection XOR A_REVERSE set */
585 rev
^= !!(attr
& A_REVERSE
);
587 /* Determine which GC to use - normal or italic */
589 gc
= (attr
& A_ITALIC
) ? italic_gc
: normal_gc
;
593 XSetForeground(XCURSESDISPLAY
, gc
, colors
[rev
? back
: fore
]);
594 XSetBackground(XCURSESDISPLAY
, gc
, colors
[rev
? fore
: back
]);
596 _make_xy(col
, row
, &xpos
, &ypos
);
603 XCURSESDISPLAY
, XCURSESWIN
, gc
, xpos
, ypos
, text
, len
);
605 /* Underline, etc. */
607 if (attr
& (A_LEFTLINE
|A_RIGHTLINE
|A_UNDERLINE
))
611 if (SP
->line_color
!= -1)
612 XSetForeground(XCURSESDISPLAY
, gc
, colors
[SP
->line_color
]);
614 if (attr
& A_UNDERLINE
) /* UNDER */
615 XDrawLine(XCURSESDISPLAY
, XCURSESWIN
, gc
,
616 xpos
, ypos
+ 1, xpos
+ font_width
* len
, ypos
+ 1);
618 if (attr
& A_LEFTLINE
) /* LEFT */
619 for (k
= 0; k
< len
; k
++)
621 int x
= xpos
+ font_width
* k
- 1;
622 XDrawLine(XCURSESDISPLAY
, XCURSESWIN
, gc
,
623 x
, ypos
- font_ascent
, x
, ypos
+ font_descent
);
626 if (attr
& A_RIGHTLINE
) /* RIGHT */
627 for (k
= 0; k
< len
; k
++)
629 int x
= xpos
+ font_width
* (k
+ 1) - 1;
630 XDrawLine(XCURSESDISPLAY
, XCURSESWIN
, gc
,
631 x
, ypos
- font_ascent
, x
, ypos
+ font_descent
);
635 PDC_LOG(("%s:_new_packet() - row: %d col: %d "
636 "num_cols: %d fore: %d back: %d text:<%s>\n",
637 XCLOGMSG
, row
, col
, len
, fore
, back
, text
));
642 /* The core display routine -- update one line of text */
644 static int _display_text(const chtype
*ch
, int row
, int col
,
645 int num_cols
, bool highlight
)
652 chtype old_attr
, attr
;
655 PDC_LOG(("%s:_display_text() - called: row: %d col: %d "
656 "num_cols: %d\n", XCLOGMSG
, row
, col
, num_cols
));
661 old_attr
= *ch
& A_ATTRIBUTES
;
663 for (i
= 0, j
= 0; j
< num_cols
; j
++)
667 attr
= curr
& A_ATTRIBUTES
;
670 if (attr
& A_ALTCHARSET
&& !(curr
& 0xff80))
672 attr
^= A_ALTCHARSET
;
673 curr
= acs_map
[curr
& 0x7f];
678 /* Special handling for ACS_BLOCK */
680 if (!(curr
& A_CHARTEXT
))
686 if (attr
!= old_attr
)
688 if (_new_packet(old_attr
, highlight
, i
, col
, row
, text
) == ERR
)
697 text
[i
].byte1
= (curr
& 0xff00) >> 8;
698 text
[i
++].byte2
= curr
& 0x00ff;
700 text
[i
++] = curr
& 0xff;
704 return _new_packet(old_attr
, highlight
, i
, col
, row
, text
);
707 static void _get_gc(GC
*gc
, XFontStruct
*font_info
, int fore
, int back
)
711 /* Create default Graphics Context */
713 *gc
= XCreateGC(XCURSESDISPLAY
, XCURSESWIN
, 0L, &values
);
717 XSetFont(XCURSESDISPLAY
, *gc
, font_info
->fid
);
719 XSetForeground(XCURSESDISPLAY
, *gc
, colors
[fore
]);
720 XSetBackground(XCURSESDISPLAY
, *gc
, colors
[back
]);
723 static void _initialize_colors(void)
725 colors
[COLOR_BLACK
] = xc_app_data
.colorBlack
;
726 colors
[COLOR_RED
] = xc_app_data
.colorRed
;
727 colors
[COLOR_GREEN
] = xc_app_data
.colorGreen
;
728 colors
[COLOR_YELLOW
] = xc_app_data
.colorYellow
;
729 colors
[COLOR_BLUE
] = xc_app_data
.colorBlue
;
730 colors
[COLOR_MAGENTA
] = xc_app_data
.colorMagenta
;
731 colors
[COLOR_CYAN
] = xc_app_data
.colorCyan
;
732 colors
[COLOR_WHITE
] = xc_app_data
.colorWhite
;
734 colors
[COLOR_BLACK
+ 8] = xc_app_data
.colorBoldBlack
;
735 colors
[COLOR_RED
+ 8] = xc_app_data
.colorBoldRed
;
736 colors
[COLOR_GREEN
+ 8] = xc_app_data
.colorBoldGreen
;
737 colors
[COLOR_YELLOW
+ 8] = xc_app_data
.colorBoldYellow
;
738 colors
[COLOR_BLUE
+ 8] = xc_app_data
.colorBoldBlue
;
739 colors
[COLOR_MAGENTA
+ 8] = xc_app_data
.colorBoldMagenta
;
740 colors
[COLOR_CYAN
+ 8] = xc_app_data
.colorBoldCyan
;
741 colors
[COLOR_WHITE
+ 8] = xc_app_data
.colorBoldWhite
;
743 colors
[COLOR_CURSOR
] = xc_app_data
.cursorColor
;
744 colors
[COLOR_BORDER
] = xc_app_data
.borderColor
;
747 static void _refresh_scrollbar(void)
749 XC_LOG(("_refresh_scrollbar() - called\n"));
753 PDC_SCROLLBAR_TYPE total_y
= SP
->sb_total_y
;
754 PDC_SCROLLBAR_TYPE total_x
= SP
->sb_total_x
;
757 XawScrollbarSetThumb(scrollVert
,
758 (PDC_SCROLLBAR_TYPE
)(SP
->sb_cur_y
) / total_y
,
759 (PDC_SCROLLBAR_TYPE
)(SP
->sb_viewport_y
) / total_y
);
762 XawScrollbarSetThumb(scrollHoriz
,
763 (PDC_SCROLLBAR_TYPE
)(SP
->sb_cur_x
) / total_x
,
764 (PDC_SCROLLBAR_TYPE
)(SP
->sb_viewport_x
) / total_x
);
768 static void _set_cursor_color(chtype
*ch
, short *fore
, short *back
)
773 attr
= PAIR_NUMBER(*ch
);
777 PDC_pair_content(attr
, &f
, &b
);
796 static void _get_icon(void)
798 XIconSize
*icon_size
;
801 unsigned char *bitmap_bits
= NULL
;
802 unsigned icon_bitmap_width
= 0, icon_bitmap_height
= 0,
803 file_bitmap_width
= 0, file_bitmap_height
= 0;
805 XC_LOG(("_get_icon() - called\n"));
807 icon_size
= XAllocIconSize();
809 rc
= XGetIconSizes(XtDisplay(topLevel
),
810 RootWindowOfScreen(XtScreen(topLevel
)),
811 &icon_size
, &size_count
);
813 /* if the WM can advise on icon sizes... */
815 if (rc
&& size_count
)
817 int i
, max_height
= 0, max_width
= 0;
819 PDC_LOG(("%s:size_count: %d rc: %d\n", XCLOGMSG
, size_count
, rc
));
821 for (i
= 0; i
< size_count
; i
++)
823 if (icon_size
[i
].max_width
> max_width
)
824 max_width
= icon_size
[i
].max_width
;
825 if (icon_size
[i
].max_height
> max_height
)
826 max_height
= icon_size
[i
].max_height
;
828 PDC_LOG(("%s:min: %d %d\n", XCLOGMSG
,
829 icon_size
[i
].min_width
, icon_size
[i
].min_height
));
831 PDC_LOG(("%s:max: %d %d\n", XCLOGMSG
,
832 icon_size
[i
].max_width
, icon_size
[i
].max_height
));
834 PDC_LOG(("%s:inc: %d %d\n", XCLOGMSG
,
835 icon_size
[i
].width_inc
, icon_size
[i
].height_inc
));
838 if (max_width
>= big_icon_width
&& max_height
>= big_icon_height
)
840 icon_bitmap_width
= big_icon_width
;
841 icon_bitmap_height
= big_icon_height
;
842 bitmap_bits
= (unsigned char *)big_icon_bits
;
846 icon_bitmap_width
= little_icon_width
;
847 icon_bitmap_height
= little_icon_height
;
848 bitmap_bits
= (unsigned char *)little_icon_bits
;
852 else /* use small icon */
854 icon_bitmap_width
= little_icon_width
;
855 icon_bitmap_height
= little_icon_height
;
856 bitmap_bits
= (unsigned char *)little_icon_bits
;
862 if (xc_app_data
.pixmap
&& xc_app_data
.pixmap
[0]) /* supplied pixmap */
864 XpmReadFileToPixmap(XtDisplay(topLevel
),
865 RootWindowOfScreen(XtScreen(topLevel
)),
866 (char *)xc_app_data
.pixmap
,
867 &icon_pixmap
, &icon_pixmap_mask
, NULL
);
872 if (xc_app_data
.bitmap
&& xc_app_data
.bitmap
[0]) /* supplied bitmap */
874 int x_hot
= 0, y_hot
= 0;
876 rc
= XReadBitmapFile(XtDisplay(topLevel
),
877 RootWindowOfScreen(XtScreen(topLevel
)),
878 (char *)xc_app_data
.bitmap
,
879 &file_bitmap_width
, &file_bitmap_height
,
880 &icon_bitmap
, &x_hot
, &y_hot
);
884 case BitmapOpenFailed
:
885 fprintf(stderr
, "bitmap file %s: not found\n",
888 case BitmapFileInvalid
:
889 fprintf(stderr
, "bitmap file %s: contents invalid\n",
897 icon_bitmap
= XCreateBitmapFromData(XtDisplay(topLevel
),
898 RootWindowOfScreen(XtScreen(topLevel
)),
899 (char *)bitmap_bits
, icon_bitmap_width
, icon_bitmap_height
);
902 static void _draw_border(void)
904 /* Draw the border if required */
906 if (xc_app_data
.borderWidth
)
907 XDrawRectangle(XCURSESDISPLAY
, XCURSESWIN
, border_gc
,
908 xc_app_data
.borderWidth
/ 2,
909 xc_app_data
.borderWidth
/ 2,
910 window_width
- xc_app_data
.borderWidth
,
911 window_height
- xc_app_data
.borderWidth
);
914 /* Redraw the entire screen */
916 static void _display_screen(void)
920 XC_LOG(("_display_screen() - called\n"));
922 for (row
= 0; row
< XCursesLINES
; row
++)
924 XC_get_line_lock(row
);
926 _display_text((const chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(row
)),
927 row
, 0, COLS
, FALSE
);
929 XC_release_line_lock(row
);
936 /* Draw changed portions of the screen */
938 static void _refresh_screen(void)
940 int row
, start_col
, num_cols
;
942 XC_LOG(("_refresh_screen() - called\n"));
944 for (row
= 0; row
< XCursesLINES
; row
++)
946 num_cols
= (int)*(Xcurscr
+ XCURSCR_LENGTH_OFF
+ row
);
950 XC_get_line_lock(row
);
952 start_col
= (int)*(Xcurscr
+ XCURSCR_START_OFF
+ row
);
954 _display_text((const chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(row
) +
955 (start_col
* sizeof(chtype
))), row
, start_col
,
958 *(Xcurscr
+ XCURSCR_LENGTH_OFF
+ row
) = 0;
960 XC_release_line_lock(row
);
968 static void _handle_expose(Widget w
, XtPointer client_data
, XEvent
*event
,
971 XC_LOG(("_handle_expose() - called\n"));
973 /* ignore all Exposes except last */
975 if (event
->xexpose
.count
)
978 if (after_first_curses_request
&& received_map_notify
)
982 static void _handle_nonmaskable(Widget w
, XtPointer client_data
, XEvent
*event
,
985 XClientMessageEvent
*client_event
= (XClientMessageEvent
*)event
;
987 PDC_LOG(("%s:_handle_nonmaskable called: xc_otherpid %d event %d\n",
988 XCLOGMSG
, xc_otherpid
, event
->type
));
990 if (event
->type
== ClientMessage
)
992 XC_LOG(("ClientMessage received\n"));
994 /* This code used to include handling of WM_SAVE_YOURSELF, but
995 it resulted in continual failure of THE on my Toshiba laptop.
996 Removed on 3-3-2001. Now only exits on WM_DELETE_WINDOW. */
998 if ((Atom
)client_event
->data
.s
[0] == wm_atom
[0])
999 _exit_process(0, SIGKILL
, "");
1003 static void XCursesKeyPress(Widget w
, XEvent
*event
, String
*params
,
1006 enum { STATE_NORMAL
, STATE_COMPOSE
, STATE_CHAR
};
1010 wchar_t buffer
[120];
1012 unsigned char buffer
[120];
1013 XComposeStatus compose
;
1014 static int compose_state
= STATE_NORMAL
;
1015 static int compose_index
= 0;
1018 unsigned long key
= 0;
1021 unsigned long modifier
= 0;
1022 bool key_code
= FALSE
;
1024 XC_LOG(("XCursesKeyPress() - called\n"));
1026 /* Handle modifier keys first; ignore other KeyReleases */
1028 if (event
->type
== KeyRelease
)
1030 /* The keysym value was set by a previous call to this function
1031 with a KeyPress event (or reset by the mouse event handler) */
1033 if (SP
->return_key_modifiers
&&
1035 keysym
!= compose_key
&&
1037 IsModifierKey(keysym
))
1047 key
= KEY_CONTROL_L
;
1050 key
= KEY_CONTROL_R
;
1060 _send_key_to_curses(key
, NULL
, TRUE
);
1069 count
= XwcLookupString(Xic
, &(event
->xkey
), buffer
, buflen
,
1072 count
= XLookupString(&(event
->xkey
), (char *)buffer
, buflen
,
1076 /* translate keysym into curses key code */
1078 PDC_LOG(("%s:Key mask: %x\n", XCLOGMSG
, event
->xkey
.state
));
1081 for (i
= 0; i
< 4; i
++)
1082 PDC_debug("%s:Keysym %x %d\n", XCLOGMSG
,
1083 XKeycodeToKeysym(XCURSESDISPLAY
, event
->xkey
.keycode
, i
), i
);
1088 /* Check if the key just pressed is the user-specified compose
1089 key; if it is, set the compose state and exit. */
1091 if (keysym
== compose_key
)
1094 int xpos
, ypos
, save_visibility
= SP
->visibility
;
1095 short fore
= 0, back
= 0;
1097 /* Change the shape of the cursor to an outline rectangle to
1098 indicate we are in "compose" status */
1104 SP
->visibility
= save_visibility
;
1105 _make_xy(SP
->curscol
, SP
->cursrow
, &xpos
, &ypos
);
1107 ch
= (chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(SP
->cursrow
) +
1108 (SP
->curscol
* sizeof(chtype
)));
1110 _set_cursor_color(ch
, &fore
, &back
);
1112 XSetForeground(XCURSESDISPLAY
, rect_cursor_gc
, colors
[back
]);
1114 XDrawRectangle(XCURSESDISPLAY
, XCURSESWIN
, rect_cursor_gc
,
1115 xpos
+ 1, ypos
- font_height
+
1116 xc_app_data
.normalFont
->descent
+ 1,
1117 font_width
- 2, font_height
- 2);
1119 compose_state
= STATE_COMPOSE
;
1123 switch (compose_state
)
1126 if (IsModifierKey(keysym
))
1129 if (event
->xkey
.state
& compose_mask
)
1131 compose_state
= STATE_NORMAL
;
1136 if (buffer
[0] && count
== 1)
1141 for (i
= 0; i
< (int)strlen(compose_chars
); i
++)
1142 if (compose_chars
[i
] == key
)
1148 if (compose_index
== -1)
1150 compose_state
= STATE_NORMAL
;
1156 compose_state
= STATE_CHAR
;
1160 if (IsModifierKey(keysym
))
1163 if (event
->xkey
.state
& compose_mask
)
1165 compose_state
= STATE_NORMAL
;
1170 if (buffer
[0] && count
== 1)
1175 for (i
= 0; i
< MAX_COMPOSE_CHARS
; i
++)
1176 if (compose_lookups
[compose_index
][i
] == key
)
1184 compose_state
= STATE_NORMAL
;
1190 _send_key_to_curses(compose_keys
[compose_index
][char_idx
],
1193 compose_state
= STATE_NORMAL
;
1201 #endif /* PDC_XIM */
1203 /* To get here we are procesing "normal" keys */
1205 PDC_LOG(("%s:Keysym %x %d\n", XCLOGMSG
,
1206 XKeycodeToKeysym(XCURSESDISPLAY
, event
->xkey
.keycode
, key
), key
));
1208 if (SP
->save_key_modifiers
)
1210 /* 0x10: usually, numlock modifier */
1212 if (event
->xkey
.state
& Mod2Mask
)
1213 modifier
|= PDC_KEY_MODIFIER_NUMLOCK
;
1215 /* 0x01: shift modifier */
1217 if (event
->xkey
.state
& ShiftMask
)
1218 modifier
|= PDC_KEY_MODIFIER_SHIFT
;
1220 /* 0x04: control modifier */
1222 if (event
->xkey
.state
& ControlMask
)
1223 modifier
|= PDC_KEY_MODIFIER_CONTROL
;
1225 /* 0x08: usually, alt modifier */
1227 if (event
->xkey
.state
& Mod1Mask
)
1228 modifier
|= PDC_KEY_MODIFIER_ALT
;
1231 for (i
= 0; key_table
[i
].keycode
; i
++)
1233 if (key_table
[i
].keycode
== keysym
)
1235 PDC_LOG(("%s:State %x\n", XCLOGMSG
, event
->xkey
.state
));
1237 /* ControlMask: 0x04: control modifier
1238 Mod1Mask: 0x08: usually, alt modifier
1239 Mod2Mask: 0x10: usually, numlock modifier
1240 ShiftMask: 0x01: shift modifier */
1242 if ((event
->xkey
.state
& ShiftMask
) ||
1243 (key_table
[i
].numkeypad
&&
1244 (event
->xkey
.state
& Mod2Mask
)))
1246 key
= key_table
[i
].shifted
;
1248 else if (event
->xkey
.state
& ControlMask
)
1250 key
= key_table
[i
].control
;
1252 else if (event
->xkey
.state
& Mod1Mask
)
1254 key
= key_table
[i
].alt
;
1257 /* To get here, we ignore all other modifiers */
1260 key
= key_table
[i
].normal
;
1262 key_code
= (key
> 0x100);
1267 if (!key
&& buffer
[0] && count
== 1)
1270 PDC_LOG(("%s:Key: %s pressed - %x Mod: %x\n", XCLOGMSG
,
1271 XKeysymToString(keysym
), key
, event
->xkey
.state
));
1273 /* Handle ALT letters and numbers */
1275 if (event
->xkey
.state
== Mod1Mask
)
1277 if (key
>= 'A' && key
<= 'Z')
1283 if (key
>= 'a' && key
<= 'z')
1289 if (key
>= '0' && key
<= '9')
1296 /* After all that, send the key back to the application if is
1301 key
|= (modifier
<< 24);
1303 _send_key_to_curses(key
, NULL
, key_code
);
1307 static void XCursesHandleString(Widget w
, XEvent
*event
, String
*params
,
1315 ptr
= (unsigned char *)*params
;
1317 if (ptr
[0] == '0' && ptr
[1] == 'x' && ptr
[2] != '\0')
1320 unsigned long total
= 0;
1322 for (ptr
+= 2; (c
= tolower(*ptr
)); ptr
++)
1326 if (c
>= '0' && c
<= '9')
1329 if (c
>= 'a' && c
<= 'f')
1330 total
+= c
- ('a' - 10);
1336 _send_key_to_curses(total
, NULL
, FALSE
);
1340 _send_key_to_curses((unsigned long)*ptr
, NULL
, FALSE
);
1343 static void _paste_string(Widget w
, XtPointer data
, Atom
*selection
, Atom
*type
,
1344 XtPointer value
, unsigned long *length
, int *format
)
1346 unsigned long i
, key
;
1347 unsigned char *string
= value
;
1349 XC_LOG(("_paste_string() - called\n"));
1351 if (!*type
|| !*length
|| !string
)
1354 for (i
= 0; string
[i
] && (i
< (*length
)); i
++)
1358 if (key
== 10) /* new line - convert to ^M */
1361 _send_key_to_curses(key
, NULL
, FALSE
);
1367 static void _paste_utf8(Widget w
, XtPointer event
, Atom
*selection
, Atom
*type
,
1368 XtPointer value
, unsigned long *length
, int *format
)
1372 char *string
= value
;
1374 XC_LOG(("_paste_utf8() - called\n"));
1376 if (!*type
|| !*length
)
1378 XtGetSelectionValue(w
, XA_PRIMARY
, XA_STRING
, _paste_string
,
1379 event
, ((XButtonEvent
*)event
)->time
);
1388 while (string
[i
] && (i
< len
))
1390 int retval
= _from_utf8(&key
, string
+ i
, len
- i
);
1395 if (key
== 10) /* new line - convert to ^M */
1398 _send_key_to_curses(key
, NULL
, FALSE
);
1406 static void XCursesPasteSelection(Widget w
, XButtonEvent
*button_event
)
1408 XC_LOG(("XCursesPasteSelection() - called\n"));
1410 XtGetSelectionValue(w
, XA_PRIMARY
, XA_UTF8_STRING(XtDisplay(w
)),
1411 _paste_utf8
, (XtPointer
)button_event
,
1412 button_event
->time
);
1415 static Boolean
_convert_proc(Widget w
, Atom
*selection
, Atom
*target
,
1416 Atom
*type_return
, XtPointer
*value_return
,
1417 unsigned long *length_return
, int *format_return
)
1419 XC_LOG(("_convert_proc() - called\n"));
1421 if (*target
== XA_TARGETS(XtDisplay(topLevel
)))
1423 XSelectionRequestEvent
*req
= XtGetSelectionRequest(w
,
1424 *selection
, (XtRequestId
)NULL
);
1427 XPointer std_targets
;
1428 unsigned long std_length
;
1430 XmuConvertStandardSelection(topLevel
, req
->time
, selection
,
1431 target
, type_return
, &std_targets
,
1432 &std_length
, format_return
);
1434 *length_return
= std_length
+ 2;
1435 *value_return
= XtMalloc(sizeof(Atom
) * (*length_return
));
1437 targetP
= *(Atom
**)value_return
;
1438 *targetP
++ = XA_STRING
;
1439 *targetP
++ = XA_UTF8_STRING(XtDisplay(topLevel
));
1441 memmove((void *)targetP
, (const void *)std_targets
,
1442 sizeof(Atom
) * std_length
);
1444 XtFree((char *)std_targets
);
1445 *type_return
= XA_ATOM
;
1446 *format_return
= sizeof(Atom
) * 8;
1450 else if (*target
== XA_UTF8_STRING(XtDisplay(topLevel
)) ||
1451 *target
== XA_STRING
)
1453 bool utf8
= !(*target
== XA_STRING
);
1454 char *data
= XtMalloc(tmpsel_length
* 3 + 1);
1455 chtype
*tmp
= tmpsel
;
1461 ret_length
+= _to_utf8(data
+ ret_length
, *tmp
++);
1465 data
[ret_length
++] = *tmp
++ & 0xff;
1467 data
[ret_length
++] = '\0';
1469 *value_return
= data
;
1470 *length_return
= ret_length
;
1472 *type_return
= *target
;
1477 return XmuConvertStandardSelection(topLevel
, CurrentTime
,
1478 selection
, target
, type_return
, (XPointer
*)value_return
,
1479 length_return
, format_return
);
1482 static void _lose_ownership(Widget w
, Atom
*type
)
1484 XC_LOG(("_lose_ownership() - called\n"));
1494 static void _show_selection(int start_x
, int start_y
, int end_x
, int end_y
,
1497 int i
, num_cols
, start_col
, row
;
1499 PDC_LOG(("%s:_show_selection() - called StartX: %d StartY: %d "
1500 "EndX: %d EndY: %d Highlight: %d\n", XCLOGMSG
,
1501 start_x
, start_y
, end_x
, end_y
, highlight
));
1503 for (i
= 0; i
< end_y
- start_y
+ 1; i
++)
1505 if (start_y
== end_y
) /* only one line */
1507 start_col
= start_x
;
1508 num_cols
= end_x
- start_x
+ 1;
1511 else if (!i
) /* first line */
1513 start_col
= start_x
;
1514 num_cols
= COLS
- start_x
;
1517 else if (start_y
+ i
== end_y
) /* last line */
1520 num_cols
= end_x
+ 1;
1523 else /* full line */
1530 XC_get_line_lock(row
);
1532 _display_text((const chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(row
) +
1533 (start_col
* sizeof(chtype
))), row
, start_col
,
1534 num_cols
, highlight
);
1536 XC_release_line_lock(row
);
1540 static void _selection_off(void)
1542 XC_LOG(("_selection_off() - called\n"));
1546 selection_start_x
= selection_start_y
= selection_end_x
=
1547 selection_end_y
= 0;
1549 mouse_selection
= FALSE
;
1552 static void _selection_on(int x
, int y
)
1554 XC_LOG(("_selection_on() - called\n"));
1556 selection_start_x
= selection_end_x
= x
;
1557 selection_start_y
= selection_end_y
= y
;
1560 static void _selection_extend(int x
, int y
)
1562 int temp
, current_start
, current_end
, current_start_x
,
1563 current_end_x
, current_start_y
, current_end_y
, new_start
,
1564 new_end
, new_start_x
, new_end_x
, new_start_y
, new_end_y
;
1566 XC_LOG(("_selection_extend() - called\n"));
1568 mouse_selection
= TRUE
;
1570 /* convert x/y coordinates into start/stop */
1572 current_start
= (selection_start_y
* COLS
) + selection_start_x
;
1573 current_end
= (selection_end_y
* COLS
) + selection_end_x
;
1575 if (current_start
> current_end
)
1577 current_start_x
= selection_end_x
;
1578 current_start_y
= selection_end_y
;
1579 current_end_x
= selection_start_x
;
1580 current_end_y
= selection_start_y
;
1581 temp
= current_start
;
1582 current_start
= current_end
;
1587 current_end_x
= selection_end_x
;
1588 current_end_y
= selection_end_y
;
1589 current_start_x
= selection_start_x
;
1590 current_start_y
= selection_start_y
;
1593 /* Now we have the current selection as a linear expression.
1594 Convert the new position to a linear expression. */
1596 selection_end_x
= x
;
1597 selection_end_y
= y
;
1599 /* convert x/y coordinates into start/stop */
1601 new_start
= (selection_start_y
* COLS
) + selection_start_x
;
1602 new_end
= (selection_end_y
* COLS
) + selection_end_x
;
1604 if (new_start
> new_end
)
1606 new_start_x
= selection_end_x
;
1607 new_start_y
= selection_end_y
;
1608 new_end_x
= selection_start_x
;
1609 new_end_y
= selection_start_y
;
1611 new_start
= new_end
;
1616 new_end_x
= selection_end_x
;
1617 new_end_y
= selection_end_y
;
1618 new_start_x
= selection_start_x
;
1619 new_start_y
= selection_start_y
;
1622 if (new_end
> current_end
)
1623 _show_selection(current_end_x
, current_end_y
, new_end_x
,
1625 else if (new_end
< current_end
)
1626 _show_selection(new_end_x
, new_end_y
, current_end_x
,
1627 current_end_y
, FALSE
);
1628 else if (new_start
< current_start
)
1629 _show_selection(new_start_x
, new_start_y
, current_start_x
,
1630 current_start_y
, TRUE
);
1631 else if (new_start
> current_start
)
1632 _show_selection(current_start_x
, current_start_y
,
1633 new_start_x
, new_start_y
, FALSE
);
1635 _show_selection(current_start_x
, current_start_y
,
1636 new_start_x
, new_start_y
, TRUE
);
1639 static void _selection_set(void)
1641 int i
, j
, start
, end
, start_x
, end_x
, start_y
, end_y
, num_cols
,
1642 start_col
, row
, num_chars
, ch
, last_nonblank
, length
, newlen
;
1645 XC_LOG(("_selection_set() - called\n"));
1647 /* convert x/y coordinates into start/stop */
1649 start
= (selection_start_y
* COLS
) + selection_start_x
;
1650 end
= (selection_end_y
* COLS
) + selection_end_x
;
1665 start_x
= selection_end_x
;
1666 start_y
= selection_end_y
;
1667 end_x
= selection_start_x
;
1668 end_y
= selection_start_y
;
1669 length
= start
- end
+ 1;
1673 end_x
= selection_end_x
;
1674 end_y
= selection_end_y
;
1675 start_x
= selection_start_x
;
1676 start_y
= selection_start_y
;
1677 length
= end
- start
+ 1;
1680 newlen
= length
+ end_y
- start_y
+ 2;
1682 if (length
> (int)tmpsel_length
)
1685 tmpsel
= malloc(newlen
* sizeof(chtype
));
1687 tmpsel
= realloc(tmpsel
, newlen
* sizeof(chtype
));
1696 tmpsel_length
= length
;
1699 for (i
= 0; i
< end_y
- start_y
+ 1; i
++)
1702 if (start_y
== end_y
) /* only one line */
1704 start_col
= start_x
;
1705 num_cols
= end_x
- start_x
+ 1;
1708 else if (!i
) /* first line */
1710 start_col
= start_x
;
1711 num_cols
= COLS
- start_x
;
1714 else if (start_y
+ i
== end_y
) /* last line */
1717 num_cols
= end_x
+ 1;
1720 else /* full line */
1727 XC_get_line_lock(row
);
1729 ptr
= (chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(row
) +
1730 start_col
* sizeof(chtype
));
1732 if (i
< end_y
- start_y
)
1736 for (j
= 0; j
< num_cols
; j
++)
1738 ch
= (int)(ptr
[j
] & A_CHARTEXT
);
1744 last_nonblank
= num_cols
- 1;
1746 for (j
= 0; j
<= last_nonblank
; j
++)
1747 tmpsel
[num_chars
++] = ptr
[j
];
1749 XC_release_line_lock(row
);
1751 if (i
< end_y
- start_y
)
1752 tmpsel
[num_chars
++] = '\n';
1755 tmpsel
[num_chars
] = '\0';
1756 tmpsel_length
= num_chars
;
1759 static void _display_cursor(int old_row
, int old_x
, int new_row
, int new_x
)
1763 short fore
= 0, back
= 0;
1765 PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1766 XCLOGMSG
, old_row
, old_x
));
1768 /* if the cursor position is outside the boundary of the screen,
1769 ignore the request */
1771 if (old_row
>= XCursesLINES
|| old_x
>= COLS
||
1772 new_row
>= XCursesLINES
|| new_x
>= COLS
)
1775 /* display the character at the current cursor position */
1777 PDC_LOG(("%s:_display_cursor() - draw char at row: %d col %d\n",
1778 XCLOGMSG
, old_row
, old_x
));
1780 _display_text((const chtype
*)(Xcurscr
+ (XCURSCR_Y_OFF(old_row
) +
1781 (old_x
* sizeof(chtype
)))), old_row
, old_x
, 1, FALSE
);
1783 /* display the cursor at the new cursor position */
1785 if (!SP
->visibility
)
1786 return; /* cursor not displayed, no more to do */
1788 _make_xy(new_x
, new_row
, &xpos
, &ypos
);
1790 ch
= (chtype
*)(Xcurscr
+ XCURSCR_Y_OFF(new_row
) + new_x
* sizeof(chtype
));
1792 _set_cursor_color(ch
, &fore
, &back
);
1794 if (vertical_cursor
)
1796 XSetForeground(XCURSESDISPLAY
, rect_cursor_gc
, colors
[back
]);
1798 for (i
= 1; i
<= SP
->visibility
; i
++)
1799 XDrawLine(XCURSESDISPLAY
, XCURSESWIN
, rect_cursor_gc
,
1800 xpos
+ i
, ypos
- xc_app_data
.normalFont
->ascent
,
1801 xpos
+ i
, ypos
- xc_app_data
.normalFont
->ascent
+
1806 if (SP
->visibility
== 1)
1808 /* cursor visibility normal */
1810 XSetForeground(XCURSESDISPLAY
, rect_cursor_gc
, colors
[back
]);
1812 for (i
= 0; i
< xc_app_data
.normalFont
->descent
+ 2; i
++)
1813 XDrawLine(XCURSESDISPLAY
, XCURSESWIN
, rect_cursor_gc
,
1814 xpos
, ypos
- 2 + i
, xpos
+ font_width
, ypos
- 2 + i
);
1818 /* cursor visibility high */
1822 buf
[0].byte1
= (*ch
& 0xff00) >> 8;
1823 buf
[0].byte2
= *ch
& 0x00ff;
1825 buf
[1].byte1
= buf
[1].byte2
= 0;
1829 buf
[0] = *ch
& 0xff;
1832 XSetForeground(XCURSESDISPLAY
, block_cursor_gc
, colors
[fore
]);
1833 XSetBackground(XCURSESDISPLAY
, block_cursor_gc
, colors
[back
]);
1839 XCURSESDISPLAY
, XCURSESWIN
, block_cursor_gc
,
1840 xpos
, ypos
, buf
, 1);
1844 PDC_LOG(("%s:_display_cursor() - draw cursor at row %d col %d\n",
1845 XCLOGMSG
, new_row
, new_x
));
1848 static void _redraw_cursor(void)
1850 _display_cursor(SP
->cursrow
, SP
->curscol
, SP
->cursrow
, SP
->curscol
);
1853 static void _handle_enter_leave(Widget w
, XtPointer client_data
,
1854 XEvent
*event
, Boolean
*unused
)
1856 XC_LOG(("_handle_enter_leave called\n"));
1861 XC_LOG(("EnterNotify received\n"));
1863 window_entered
= TRUE
;
1867 XC_LOG(("LeaveNotify received\n"));
1869 window_entered
= FALSE
;
1871 /* Display the cursor so it stays on while the window is
1878 PDC_LOG(("%s:_handle_enter_leave - unknown event %d\n",
1879 XCLOGMSG
, event
->type
));
1883 static void _send_key_to_curses(unsigned long key
, MOUSE_STATUS
*ms
,
1886 PDC_LOG(("%s:_send_key_to_curses() - called: sending %d\n",
1889 SP
->key_code
= key_code
;
1891 if (XC_write_socket(xc_key_sock
, &key
, sizeof(unsigned long)) < 0)
1892 _exit_process(1, SIGKILL
, "exiting from _send_key_to_curses");
1896 MOUSE_LOG(("%s:writing mouse stuff\n", XCLOGMSG
));
1898 if (XC_write_socket(xc_key_sock
, ms
, sizeof(MOUSE_STATUS
)) < 0)
1899 _exit_process(1, SIGKILL
, "exiting from _send_key_to_curses");
1903 static void _blink_cursor(XtPointer unused
, XtIntervalId
*id
)
1905 XC_LOG(("_blink_cursor() - called:\n"));
1911 /* Cursor currently ON, turn it off */
1913 int save_visibility
= SP
->visibility
;
1916 SP
->visibility
= save_visibility
;
1917 visible_cursor
= FALSE
;
1921 /* Cursor currently OFF, turn it on */
1924 visible_cursor
= TRUE
;
1928 XtAppAddTimeOut(app_context
, xc_app_data
.cursorBlinkRate
,
1929 _blink_cursor
, NULL
);
1932 static void XCursesButton(Widget w
, XEvent
*event
, String
*params
,
1936 static int last_button_no
= 0;
1937 static Time last_button_press_time
= 0;
1938 MOUSE_STATUS save_mouse_status
;
1939 bool send_key
= TRUE
;
1940 static bool remove_release
;
1941 static bool handle_real_release
;
1943 XC_LOG(("XCursesButton() - called\n"));
1945 keysym
= 0; /* suppress any modifier key return */
1947 save_mouse_status
= Mouse_status
;
1948 button_no
= event
->xbutton
.button
;
1950 /* It appears that under X11R6 (at least on Linux), that an
1951 event_type of ButtonMotion does not include the mouse button in
1952 the event. The following code is designed to cater for this
1956 button_no
= last_button_no
;
1958 last_button_no
= button_no
;
1960 Mouse_status
.changes
= 0;
1965 /* Handle button 4 and 5, which are normally mapped to the wheel
1966 mouse scroll up and down */
1968 if (button_no
== 4 || button_no
== 5)
1970 /* Send the KEY_MOUSE to curses program */
1972 memset(&Mouse_status
, 0, sizeof(Mouse_status
));
1974 Mouse_status
.changes
= (button_no
== 5) ?
1975 PDC_MOUSE_WHEEL_DOWN
: PDC_MOUSE_WHEEL_UP
;
1977 MOUSE_X_POS
= MOUSE_Y_POS
= -1;
1978 _send_key_to_curses(KEY_MOUSE
, &Mouse_status
, TRUE
);
1979 remove_release
= TRUE
;
1984 if (button_no
== 2 &&
1985 (!SP
->_trap_mbe
|| (event
->xbutton
.state
& ShiftMask
)))
1987 XCursesPasteSelection(drawing
, (XButtonEvent
*)event
);
1988 remove_release
= TRUE
;
1993 remove_release
= False
;
1994 handle_real_release
= False
;
1996 MOUSE_LOG(("\nButtonPress\n"));
1998 if ((event
->xbutton
.time
- last_button_press_time
) <
1999 xc_app_data
.doubleClickPeriod
)
2001 MOUSE_X_POS
= save_mouse_status
.x
;
2002 MOUSE_Y_POS
= save_mouse_status
.y
;
2003 BUTTON_STATUS(button_no
) = BUTTON_DOUBLE_CLICKED
;
2006 remove_release
= True
;
2010 napms(SP
->mouse_wait
);
2011 event
->type
= ButtonRelease
;
2012 XSendEvent(event
->xbutton
.display
, event
->xbutton
.window
,
2014 last_button_press_time
= event
->xbutton
.time
;
2019 last_button_press_time
= event
->xbutton
.time
;
2023 MOUSE_LOG(("\nMotionNotify: y: %d x: %d Width: %d "
2024 "Height: %d\n", event
->xbutton
.y
, event
->xbutton
.x
,
2025 font_width
, font_height
));
2027 MOUSE_X_POS
= (event
->xbutton
.x
- xc_app_data
.borderWidth
) /
2029 MOUSE_Y_POS
= (event
->xbutton
.y
- xc_app_data
.borderWidth
) /
2032 if (button_no
== 1 &&
2033 (!SP
->_trap_mbe
|| (event
->xbutton
.state
& ShiftMask
)))
2035 _selection_extend(MOUSE_X_POS
, MOUSE_Y_POS
);
2041 /* Throw away mouse movements if they are in the same character
2042 position as the last mouse event, or if we are currently in
2043 the middle of a double click event. */
2045 if ((MOUSE_X_POS
== save_mouse_status
.x
&&
2046 MOUSE_Y_POS
== save_mouse_status
.y
) ||
2047 save_mouse_status
.button
[button_no
- 1] == BUTTON_DOUBLE_CLICKED
)
2053 Mouse_status
.changes
|= PDC_MOUSE_MOVED
;
2059 MOUSE_LOG(("Release at: %ld - removed\n", event
->xbutton
.time
));
2064 MOUSE_X_POS
= (event
->xbutton
.x
- xc_app_data
.borderWidth
) /
2066 MOUSE_Y_POS
= (event
->xbutton
.y
- xc_app_data
.borderWidth
) /
2069 if (!handle_real_release
)
2071 if ((event
->xbutton
.time
- last_button_press_time
) <
2073 (event
->xbutton
.time
!= last_button_press_time
))
2075 /* The "real" release was shorter than usleep() time;
2076 therefore generate a click event */
2078 MOUSE_LOG(("Release at: %ld - click\n",
2079 event
->xbutton
.time
));
2081 BUTTON_STATUS(button_no
) = BUTTON_CLICKED
;
2083 if (button_no
== 1 && mouse_selection
&&
2084 (!SP
->_trap_mbe
|| (event
->xbutton
.state
& ShiftMask
)))
2088 if (XtOwnSelection(topLevel
, XA_PRIMARY
,
2089 event
->xbutton
.time
, _convert_proc
,
2090 _lose_ownership
, NULL
) == False
)
2096 /* Ensure the "pseudo" release event is ignored */
2098 remove_release
= True
;
2099 handle_real_release
= False
;
2104 /* Button release longer than usleep() time;
2105 therefore generate a press and wait for the real
2106 release to occur later. */
2108 MOUSE_LOG(("Generated Release at: %ld - "
2109 "press & release\n", event
->xbutton
.time
));
2111 BUTTON_STATUS(button_no
) = BUTTON_PRESSED
;
2113 if (button_no
== 1 &&
2114 (!SP
->_trap_mbe
|| (event
->xbutton
.state
& ShiftMask
)))
2117 _selection_on(MOUSE_X_POS
, MOUSE_Y_POS
);
2120 handle_real_release
= True
;
2126 MOUSE_LOG(("Release at: %ld - released\n",
2127 event
->xbutton
.time
));
2131 MOUSE_LOG(("\nButtonRelease\n"));
2133 BUTTON_STATUS(button_no
) = BUTTON_RELEASED
;
2135 if (button_no
== 1 && mouse_selection
&&
2136 (!SP
->_trap_mbe
|| (event
->xbutton
.state
& ShiftMask
)))
2140 if (XtOwnSelection(topLevel
, XA_PRIMARY
,
2141 event
->xbutton
.time
, _convert_proc
,
2142 _lose_ownership
, NULL
) == False
)
2153 /* Set up the mouse status fields in preparation for sending */
2155 Mouse_status
.changes
|= 1 << (button_no
- 1);
2157 if (Mouse_status
.changes
& PDC_MOUSE_MOVED
&&
2158 BUTTON_STATUS(button_no
) == BUTTON_PRESSED
)
2159 BUTTON_STATUS(button_no
) = BUTTON_MOVED
;
2161 if (event
->xbutton
.state
& ShiftMask
)
2162 BUTTON_STATUS(button_no
) |= BUTTON_SHIFT
;
2163 if (event
->xbutton
.state
& ControlMask
)
2164 BUTTON_STATUS(button_no
) |= BUTTON_CONTROL
;
2165 if (event
->xbutton
.state
& Mod1Mask
)
2166 BUTTON_STATUS(button_no
) |= BUTTON_ALT
;
2168 /* If we are ignoring the event, or the mouse position is outside
2169 the bounds of the screen (because of the border), return here */
2171 MOUSE_LOG(("Button: %d x: %d y: %d Button status: %x "
2172 "Mouse status: %x\n", button_no
, MOUSE_X_POS
, MOUSE_Y_POS
,
2173 BUTTON_STATUS(button_no
), Mouse_status
.changes
));
2175 MOUSE_LOG(("Send: %d Button1: %x Button2: %x Button3: %x %d %d\n",
2176 send_key
, BUTTON_STATUS(1), BUTTON_STATUS(2),
2177 BUTTON_STATUS(3), XCursesLINES
, XCursesCOLS
));
2179 if (!send_key
|| MOUSE_X_POS
< 0 || MOUSE_X_POS
>= XCursesCOLS
||
2180 MOUSE_Y_POS
< 0 || MOUSE_Y_POS
>= XCursesLINES
)
2183 /* Send the KEY_MOUSE to curses program */
2185 _send_key_to_curses(KEY_MOUSE
, &Mouse_status
, TRUE
);
2188 static void _scroll_up_down(Widget w
, XtPointer client_data
,
2189 XtPointer call_data
)
2191 int pixels
= (long) call_data
;
2192 int total_y
= SP
->sb_total_y
* font_height
;
2193 int viewport_y
= SP
->sb_viewport_y
* font_height
;
2194 int cur_y
= SP
->sb_cur_y
* font_height
;
2196 /* When pixels is negative, right button pressed, move data down,
2197 thumb moves up. Otherwise, left button pressed, pixels positive,
2198 move data up, thumb down. */
2202 /* limit panning to size of overall */
2207 if (cur_y
> (total_y
- viewport_y
))
2208 cur_y
= total_y
- viewport_y
;
2210 SP
->sb_cur_y
= cur_y
/ font_height
;
2212 XawScrollbarSetThumb(w
, (double)((double)cur_y
/ (double)total_y
),
2213 (double)((double)viewport_y
/ (double)total_y
));
2215 /* Send a key: if pixels negative, send KEY_SCROLL_DOWN */
2217 _send_key_to_curses(KEY_SF
, NULL
, TRUE
);
2220 static void _scroll_left_right(Widget w
, XtPointer client_data
,
2221 XtPointer call_data
)
2223 int pixels
= (long) call_data
;
2224 int total_x
= SP
->sb_total_x
* font_width
;
2225 int viewport_x
= SP
->sb_viewport_x
* font_width
;
2226 int cur_x
= SP
->sb_cur_x
* font_width
;
2230 /* limit panning to size of overall */
2235 if (cur_x
> (total_x
- viewport_x
))
2236 cur_x
= total_x
- viewport_x
;
2238 SP
->sb_cur_x
= cur_x
/ font_width
;
2240 XawScrollbarSetThumb(w
, (double)((double)cur_x
/ (double)total_x
),
2241 (double)((double)viewport_x
/ (double)total_x
));
2243 _send_key_to_curses(KEY_SR
, NULL
, TRUE
);
2246 static void _thumb_up_down(Widget w
, XtPointer client_data
,
2247 XtPointer call_data
)
2249 double percent
= *(double *) call_data
;
2250 double total_y
= (double)SP
->sb_total_y
;
2251 double viewport_y
= (double)SP
->sb_viewport_y
;
2252 int cur_y
= SP
->sb_cur_y
;
2254 /* If the size of the viewport is > overall area simply return,
2255 as no scrolling is permitted. */
2257 if (SP
->sb_viewport_y
>= SP
->sb_total_y
)
2260 if ((SP
->sb_cur_y
= (int)((double)total_y
* percent
)) >=
2261 (total_y
- viewport_y
))
2262 SP
->sb_cur_y
= total_y
- viewport_y
;
2264 XawScrollbarSetThumb(w
, (double)(cur_y
/ total_y
),
2265 (double)(viewport_y
/ total_y
));
2267 _send_key_to_curses(KEY_SF
, NULL
, TRUE
);
2270 static void _thumb_left_right(Widget w
, XtPointer client_data
,
2271 XtPointer call_data
)
2273 double percent
= *(double *) call_data
;
2274 double total_x
= (double)SP
->sb_total_x
;
2275 double viewport_x
= (double)SP
->sb_viewport_x
;
2276 int cur_x
= SP
->sb_cur_x
;
2278 if (SP
->sb_viewport_x
>= SP
->sb_total_x
)
2281 if ((SP
->sb_cur_x
= (int)((float)total_x
* percent
)) >=
2282 (total_x
- viewport_x
))
2283 SP
->sb_cur_x
= total_x
- viewport_x
;
2285 XawScrollbarSetThumb(w
, (double)(cur_x
/ total_x
),
2286 (double)(viewport_x
/ total_x
));
2288 _send_key_to_curses(KEY_SR
, NULL
, TRUE
);
2291 static void _exit_process(int rc
, int sig
, char *msg
)
2294 fprintf(stderr
, "%s:_exit_process() - called: rc:%d sig:%d <%s>\n",
2295 XCLOGMSG
, rc
, sig
, msg
);
2298 shmdt((char *)Xcurscr
);
2299 shmctl(shmidSP
, IPC_RMID
, 0);
2300 shmctl(shmid_Xcurscr
, IPC_RMID
, 0);
2304 XFreePixmap(XCURSESDISPLAY
, icon_bitmap
);
2311 XFreePixmap(XCURSESDISPLAY
, icon_pixmap
);
2312 XFreePixmap(XCURSESDISPLAY
, icon_pixmap_mask
);
2316 XFreeGC(XCURSESDISPLAY
, normal_gc
);
2317 XFreeGC(XCURSESDISPLAY
, italic_gc
);
2318 XFreeGC(XCURSESDISPLAY
, block_cursor_gc
);
2319 XFreeGC(XCURSESDISPLAY
, rect_cursor_gc
);
2320 XFreeGC(XCURSESDISPLAY
, border_gc
);
2325 shutdown(xc_display_sock
, 2);
2326 close(xc_display_sock
);
2328 shutdown(xc_exit_sock
, 2);
2329 close(xc_exit_sock
);
2331 shutdown(xc_key_sock
, 2);
2335 kill(xc_otherpid
, sig
); /* to kill parent process */
2340 static void _resize(void)
2342 short save_atrtab
[PDC_COLOR_PAIRS
* 2];
2344 after_first_curses_request
= FALSE
;
2346 SP
->lines
= XCursesLINES
= ((resize_window_height
-
2347 (2 * xc_app_data
.borderWidth
)) / font_height
);
2349 LINES
= XCursesLINES
- SP
->linesrippedoff
- SP
->slklines
;
2351 SP
->cols
= COLS
= XCursesCOLS
= ((resize_window_width
-
2352 (2 * xc_app_data
.borderWidth
)) / font_width
);
2354 window_width
= resize_window_width
;
2355 window_height
= resize_window_height
;
2356 visible_cursor
= TRUE
;
2360 /* Detach and drop the current shared memory segment and create and
2361 attach to a new segment */
2363 memcpy(save_atrtab
, xc_atrtab
, sizeof(save_atrtab
));
2365 SP
->XcurscrSize
= XCURSCR_SIZE
;
2366 shmdt((char *)Xcurscr
);
2367 shmctl(shmid_Xcurscr
, IPC_RMID
, 0);
2369 if ((shmid_Xcurscr
= shmget(shmkey_Xcurscr
,
2370 SP
->XcurscrSize
+ XCURSESSHMMIN
, 0700 | IPC_CREAT
)) < 0)
2372 perror("Cannot allocate shared memory for curscr");
2374 _exit_process(4, SIGKILL
, "exiting from _process_curses_requests");
2377 Xcurscr
= (unsigned char*)shmat(shmid_Xcurscr
, 0, 0);
2378 memset(Xcurscr
, 0, SP
->XcurscrSize
);
2379 xc_atrtab
= (short *)(Xcurscr
+ XCURSCR_ATRTAB_OFF
);
2380 memcpy(xc_atrtab
, save_atrtab
, sizeof(save_atrtab
));
2383 /* For PDC_set_title() */
2385 static void _set_title(void)
2387 char title
[1024]; /* big enough for window title */
2390 if ((XC_read_socket(xc_display_sock
, &pos
, sizeof(int)) < 0) ||
2391 (XC_read_socket(xc_display_sock
, title
, pos
) < 0))
2393 _exit_process(5, SIGKILL
, "exiting from _set_title");
2396 XtVaSetValues(topLevel
, XtNtitle
, title
, NULL
);
2399 /* For color_content() */
2401 static void _get_color(void)
2403 XColor
*tmp
= (XColor
*)(Xcurscr
+ XCURSCR_XCOLOR_OFF
);
2404 int index
= tmp
->pixel
;
2405 Colormap cmap
= DefaultColormap(XCURSESDISPLAY
,
2406 DefaultScreen(XCURSESDISPLAY
));
2408 if (index
< 0 || index
>= MAX_COLORS
)
2409 _exit_process(4, SIGKILL
, "exiting from _get_color");
2411 tmp
->pixel
= colors
[index
];
2412 XQueryColor(XCURSESDISPLAY
, cmap
, tmp
);
2415 /* For init_color() */
2417 static void _set_color(void)
2419 XColor
*tmp
= (XColor
*)(Xcurscr
+ XCURSCR_XCOLOR_OFF
);
2420 int index
= tmp
->pixel
;
2421 Colormap cmap
= DefaultColormap(XCURSESDISPLAY
,
2422 DefaultScreen(XCURSESDISPLAY
));
2424 if (index
< 0 || index
>= MAX_COLORS
)
2425 _exit_process(4, SIGKILL
, "exiting from _set_color");
2427 if (XAllocColor(XCURSESDISPLAY
, cmap
, tmp
))
2429 XFreeColors(XCURSESDISPLAY
, cmap
, colors
+ index
, 1, 0);
2430 colors
[index
] = tmp
->pixel
;
2436 /* For PDC_getclipboard() */
2438 static void _get_selection(Widget w
, XtPointer data
, Atom
*selection
,
2439 Atom
*type
, XtPointer value
,
2440 unsigned long *length
, int *format
)
2442 unsigned char *src
= value
;
2443 int pos
, len
= *length
;
2445 XC_LOG(("_get_selection() - called\n"));
2449 if (XC_write_display_socket_int(PDC_CLIP_EMPTY
) < 0)
2450 _exit_process(4, SIGKILL
, "exiting from _get_selection");
2454 /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2457 if (XC_write_display_socket_int(PDC_CLIP_SUCCESS
) < 0)
2458 _exit_process(4, SIGKILL
, "exiting from _get_selection");
2460 if (XC_write_display_socket_int(len
) < 0)
2461 _exit_process(4, SIGKILL
, "exiting from _get_selection");
2463 for (pos
= 0; pos
< len
; pos
++)
2472 if (XC_write_socket(xc_display_sock
, &c
, sizeof(c
)) < 0)
2473 _exit_process(4, SIGKILL
, "exiting from _get_selection");
2479 static void _get_selection_utf8(Widget w
, XtPointer data
, Atom
*selection
,
2480 Atom
*type
, XtPointer value
,
2481 unsigned long *length
, int *format
)
2485 XC_LOG(("_get_selection_utf8() - called\n"));
2487 if (!*type
|| !*length
)
2489 XtGetSelectionValue(w
, XA_PRIMARY
, XA_STRING
, _get_selection
,
2490 (XtPointer
)NULL
, 0);
2496 if (XC_write_display_socket_int(PDC_CLIP_EMPTY
) >= 0)
2501 wchar_t *wcontents
= malloc((len
+ 1) * sizeof(wchar_t));
2505 while (*src
&& i
< (*length
))
2507 int retval
= _from_utf8(wcontents
+ i
, src
, len
);
2517 /* Here all is OK, send PDC_CLIP_SUCCESS, then length, then
2520 if (XC_write_display_socket_int(PDC_CLIP_SUCCESS
) >= 0)
2521 if (XC_write_display_socket_int(len
) >= 0)
2522 if (XC_write_socket(xc_display_sock
,
2523 wcontents
, len
* sizeof(wchar_t)) >= 0)
2530 _exit_process(4, SIGKILL
, "exiting from _get_selection_utf8");
2534 /* For PDC_setclipboard() */
2536 static void _set_selection(void)
2541 if (XC_read_socket(xc_display_sock
, &length
, sizeof(long)) < 0)
2542 _exit_process(5, SIGKILL
, "exiting from _set_selection");
2544 if (length
> (long)tmpsel_length
)
2547 tmpsel
= malloc((length
+ 1) * sizeof(chtype
));
2549 tmpsel
= realloc(tmpsel
, (length
+ 1) * sizeof(chtype
));
2553 if (XC_write_display_socket_int(PDC_CLIP_MEMORY_ERROR
) < 0)
2554 _exit_process(4, SIGKILL
, "exiting from _set_selection");
2556 for (pos
= 0; pos
< length
; pos
++)
2563 if (XC_read_socket(xc_display_sock
, &c
, sizeof(c
)) < 0)
2564 _exit_process(5, SIGKILL
, "exiting from _set_selection");
2569 tmpsel_length
= length
;
2572 if (XtOwnSelection(topLevel
, XA_PRIMARY
, CurrentTime
,
2573 _convert_proc
, _lose_ownership
, NULL
) == False
)
2575 status
= PDC_CLIP_ACCESS_ERROR
;
2581 status
= PDC_CLIP_SUCCESS
;
2585 if (XC_write_display_socket_int(status
) < 0)
2586 _exit_process(4, SIGKILL
, "exiting from _set_selection");
2589 /* The curses process is waiting; tell it to continue */
2591 static void _resume_curses(void)
2593 if (XC_write_display_socket_int(CURSES_CONTINUE
) < 0)
2594 _exit_process(4, SIGKILL
, "exiting from _process_curses_requests");
2597 /* The curses process sent us a message */
2599 static void _process_curses_requests(XtPointer client_data
, int *fid
,
2602 struct timeval socket_timeout
= {0};
2604 int old_row
, new_row
;
2608 char buf
[12]; /* big enough for 2 integers */
2610 XC_LOG(("_process_curses_requests() - called\n"));
2612 if (!received_map_notify
)
2615 FD_ZERO(&xc_readfds
);
2616 FD_SET(xc_display_sock
, &xc_readfds
);
2618 if ((s
= select(FD_SETSIZE
, (FD_SET_CAST
)&xc_readfds
, NULL
,
2619 NULL
, &socket_timeout
)) < 0)
2620 _exit_process(2, SIGKILL
, "exiting from _process_curses_requests"
2621 " - select failed");
2623 if (!s
) /* no requests pending - should never happen! */
2626 if (FD_ISSET(xc_display_sock
, &xc_readfds
))
2628 /* read first integer to determine total message has been
2631 XC_LOG(("_process_curses_requests() - before XC_read_socket()\n"));
2633 if (XC_read_socket(xc_display_sock
, &num_cols
, sizeof(int)) < 0)
2634 _exit_process(3, SIGKILL
, "exiting from _process_curses_requests"
2637 XC_LOG(("_process_curses_requests() - after XC_read_socket()\n"));
2639 after_first_curses_request
= TRUE
;
2643 case CURSES_EXIT
: /* request from curses to stop */
2644 XC_LOG(("CURSES_EXIT received from child\n"));
2645 _exit_process(0, 0, "XCursesProcess requested to exit by child");
2649 XC_LOG(("CURSES_BELL received from child\n"));
2650 XBell(XCURSESDISPLAY
, 50);
2653 /* request from curses to confirm completion of display */
2655 case CURSES_REFRESH
:
2656 XC_LOG(("CURSES_REFRESH received from child\n"));
2661 case CURSES_REFRESH_SCROLLBAR
:
2662 _refresh_scrollbar();
2666 XC_LOG(("CURSES_CURSOR received from child\n"));
2668 if (XC_read_socket(xc_display_sock
, buf
, sizeof(int) * 2) < 0)
2669 _exit_process(5, SIGKILL
, "exiting from CURSES_CURSOR "
2670 "_process_curses_requests");
2672 memcpy(&pos
, buf
, sizeof(int));
2673 old_row
= pos
& 0xFF;
2676 memcpy(&pos
, buf
+ sizeof(int), sizeof(int));
2677 new_row
= pos
& 0xFF;
2680 visible_cursor
= TRUE
;
2681 _display_cursor(old_row
, old_x
, new_row
, new_x
);
2684 case CURSES_DISPLAY_CURSOR
:
2685 XC_LOG(("CURSES_DISPLAY_CURSOR received from child. Vis now: "));
2686 XC_LOG((visible_cursor
? "1\n" : "0\n"));
2688 /* If the window is not active, ignore this command. The
2689 cursor will stay solid. */
2695 /* Cursor currently ON, turn it off */
2697 int save_visibility
= SP
->visibility
;
2700 SP
->visibility
= save_visibility
;
2701 visible_cursor
= FALSE
;
2705 /* Cursor currently OFF, turn it on */
2708 visible_cursor
= TRUE
;
2715 XC_LOG(("CURSES_TITLE received from child\n"));
2720 XC_LOG(("CURSES_RESIZE received from child\n"));
2725 case CURSES_GET_SELECTION
:
2726 XC_LOG(("CURSES_GET_SELECTION received from child\n"));
2730 XtGetSelectionValue(topLevel
, XA_PRIMARY
,
2732 XA_UTF8_STRING(XtDisplay(topLevel
)),
2733 _get_selection_utf8
,
2735 XA_STRING
, _get_selection
,
2737 (XtPointer
)NULL
, 0);
2741 case CURSES_SET_SELECTION
:
2742 XC_LOG(("CURSES_SET_SELECTION received from child\n"));
2746 case CURSES_CLEAR_SELECTION
:
2747 XC_LOG(("CURSES_CLEAR_SELECTION received from child\n"));
2752 case CURSES_GET_COLOR
:
2753 XC_LOG(("CURSES_GET_COLOR recieved from child\n"));
2758 case CURSES_SET_COLOR
:
2759 XC_LOG(("CURSES_SET_COLOR recieved from child\n"));
2765 PDC_LOG(("%s:Unknown request %d\n", XCLOGMSG
, num_cols
));
2770 static void _handle_structure_notify(Widget w
, XtPointer client_data
,
2771 XEvent
*event
, Boolean
*unused
)
2773 XC_LOG(("_handle_structure_notify() - called\n"));
2777 case ConfigureNotify
:
2778 XC_LOG(("ConfigureNotify received\n"));
2780 /* Window has been resized, change width and height to send to
2781 place_text and place_graphics in next Expose. Also will need
2782 to kill (SIGWINCH) curses process if screen size changes. */
2784 resize_window_width
= event
->xconfigure
.width
;
2785 resize_window_height
= event
->xconfigure
.height
;
2787 after_first_curses_request
= FALSE
;
2792 kill(xc_otherpid
, SIGWINCH
);
2794 _send_key_to_curses(KEY_RESIZE
, NULL
, TRUE
);
2798 XC_LOG(("MapNotify received\n"));
2800 received_map_notify
= 1;
2806 PDC_LOG(("%s:_handle_structure_notify - unknown event %d\n",
2807 XCLOGMSG
, event
->type
));
2811 static RETSIGTYPE
_handle_signals(int signo
)
2813 int flag
= CURSES_EXIT
;
2815 PDC_LOG(("%s:_handle_signals() - called: %d\n", XCLOGMSG
, signo
));
2817 /* Patch by: Georg Fuchs */
2819 XCursesSetSignal(signo
, _handle_signals
);
2822 if (signo
== SIGTSTP
)
2829 if (signo
== SIGCONT
)
2833 if (signo
== SIGCLD
)
2837 if (signo
== SIGTTIN
)
2841 if (signo
== SIGWINCH
)
2845 /* End of patch by: Georg Fuchs */
2847 XCursesSetSignal(signo
, SIG_IGN
);
2849 /* Send a CURSES_EXIT to myself */
2851 if (XC_write_socket(xc_exit_sock
, &flag
, sizeof(int)) < 0)
2852 _exit_process(7, signo
, "exiting from _handle_signals");
2856 static void _dummy_handler(Widget w
, XtPointer client_data
,
2857 XEvent
*event
, Boolean
*unused
)
2862 int XCursesSetupX(int argc
, char *argv
[])
2864 char *myargv
[] = {"PDCurses", NULL
};
2865 extern bool sb_started
;
2867 int italic_font_valid
;
2868 XColor pointerforecolor
, pointerbackcolor
;
2869 XrmValue rmfrom
, rmto
;
2871 int minwidth
, minheight
;
2873 XC_LOG(("XCursesSetupX called\n"));
2881 program_name
= argv
[0];
2883 /* Keep open the 'write' end of the socket so the XCurses process
2884 can send a CURSES_EXIT to itself from within the signal handler */
2886 xc_exit_sock
= xc_display_sockets
[0];
2887 xc_display_sock
= xc_display_sockets
[1];
2889 close(xc_key_sockets
[0]);
2890 xc_key_sock
= xc_key_sockets
[1];
2892 /* Trap all signals when XCurses is the child process, but only if
2893 they haven't already been ignored by the application. */
2895 for (i
= 0; i
< PDC_MAX_SIGNALS
; i
++)
2896 if (XCursesSetSignal(i
, _handle_signals
) == SIG_IGN
)
2897 XCursesSetSignal(i
, SIG_IGN
);
2899 /* Start defining X Toolkit things */
2901 #if XtSpecificationRelease > 4
2902 XtSetLanguageProc(NULL
, (XtLanguageProc
)NULL
, NULL
);
2905 /* Exit if no DISPLAY variable set */
2907 if (!getenv("DISPLAY"))
2909 fprintf(stderr
, "Error: no DISPLAY variable set\n");
2910 kill(xc_otherpid
, SIGKILL
);
2914 /* Initialise the top level widget */
2916 topLevel
= XtVaAppInitialize(&app_context
, class_name
, options
,
2917 XtNumber(options
), &argc
, argv
, NULL
, NULL
);
2919 XtVaGetApplicationResources(topLevel
, &xc_app_data
, app_resources
,
2920 XtNumber(app_resources
), NULL
);
2922 /* Check application resource values here */
2924 font_width
= xc_app_data
.normalFont
->max_bounds
.rbearing
-
2925 xc_app_data
.normalFont
->min_bounds
.lbearing
;
2927 font_height
= xc_app_data
.normalFont
->max_bounds
.ascent
+
2928 xc_app_data
.normalFont
->max_bounds
.descent
;
2930 font_ascent
= xc_app_data
.normalFont
->max_bounds
.ascent
;
2931 font_descent
= xc_app_data
.normalFont
->max_bounds
.descent
;
2933 /* Check that the italic font and normal fonts are the same size */
2934 /* This appears backwards */
2936 italic_font_valid
= font_width
!=
2937 xc_app_data
.italicFont
->max_bounds
.rbearing
-
2938 xc_app_data
.italicFont
->min_bounds
.lbearing
||
2940 xc_app_data
.italicFont
->max_bounds
.ascent
+
2941 xc_app_data
.italicFont
->max_bounds
.descent
;
2943 /* Calculate size of display window */
2945 XCursesCOLS
= xc_app_data
.cols
;
2946 XCursesLINES
= xc_app_data
.lines
;
2948 window_width
= font_width
* XCursesCOLS
+
2949 2 * xc_app_data
.borderWidth
;
2951 window_height
= font_height
* XCursesLINES
+
2952 2 * xc_app_data
.borderWidth
;
2954 minwidth
= font_width
* 2 + xc_app_data
.borderWidth
* 2;
2955 minheight
= font_height
* 2 + xc_app_data
.borderWidth
* 2;
2957 /* Set up the icon for the application; the default is an internal
2958 one for PDCurses. Then set various application level resources. */
2963 if (xc_app_data
.pixmap
&& xc_app_data
.pixmap
[0])
2964 XtVaSetValues(topLevel
, XtNminWidth
, minwidth
, XtNminHeight
,
2965 minheight
, XtNbaseWidth
, xc_app_data
.borderWidth
* 2,
2966 XtNbaseHeight
, xc_app_data
.borderWidth
* 2,
2967 XtNiconPixmap
, icon_pixmap
,
2968 XtNiconMask
, icon_pixmap_mask
, NULL
);
2971 XtVaSetValues(topLevel
, XtNminWidth
, minwidth
, XtNminHeight
,
2972 minheight
, XtNbaseWidth
, xc_app_data
.borderWidth
* 2,
2973 XtNbaseHeight
, xc_app_data
.borderWidth
* 2,
2974 XtNiconPixmap
, icon_bitmap
, NULL
);
2976 /* Create a BOX widget in which to draw */
2978 if (xc_app_data
.scrollbarWidth
&& sb_started
)
2980 scrollBox
= XtVaCreateManagedWidget(program_name
,
2981 scrollBoxWidgetClass
, topLevel
, XtNwidth
,
2982 window_width
+ xc_app_data
.scrollbarWidth
,
2983 XtNheight
, window_height
+ xc_app_data
.scrollbarWidth
,
2984 XtNwidthInc
, font_width
, XtNheightInc
, font_height
, NULL
);
2986 drawing
= XtVaCreateManagedWidget(program_name
,
2987 boxWidgetClass
, scrollBox
, XtNwidth
,
2988 window_width
, XtNheight
, window_height
, XtNwidthInc
,
2989 font_width
, XtNheightInc
, font_height
, NULL
);
2991 scrollVert
= XtVaCreateManagedWidget("scrollVert",
2992 scrollbarWidgetClass
, scrollBox
, XtNorientation
,
2993 XtorientVertical
, XtNheight
, window_height
, XtNwidth
,
2994 xc_app_data
.scrollbarWidth
, NULL
);
2996 XtAddCallback(scrollVert
, XtNscrollProc
, _scroll_up_down
, drawing
);
2997 XtAddCallback(scrollVert
, XtNjumpProc
, _thumb_up_down
, drawing
);
2999 scrollHoriz
= XtVaCreateManagedWidget("scrollHoriz",
3000 scrollbarWidgetClass
, scrollBox
, XtNorientation
,
3001 XtorientHorizontal
, XtNwidth
, window_width
, XtNheight
,
3002 xc_app_data
.scrollbarWidth
, NULL
);
3004 XtAddCallback(scrollHoriz
, XtNscrollProc
, _scroll_left_right
, drawing
);
3005 XtAddCallback(scrollHoriz
, XtNjumpProc
, _thumb_left_right
, drawing
);
3009 drawing
= XtVaCreateManagedWidget(program_name
, boxWidgetClass
,
3010 topLevel
, XtNwidth
, window_width
, XtNheight
, window_height
,
3011 XtNwidthInc
, font_width
, XtNheightInc
, font_height
, NULL
);
3013 XtVaSetValues(topLevel
, XtNwidthInc
, font_width
, XtNheightInc
,
3017 /* Process any default translations */
3019 XtAugmentTranslations(drawing
,
3020 XtParseTranslationTable(default_translations
));
3021 XtAppAddActions(app_context
, action_table
, XtNumber(action_table
));
3023 /* Process the supplied colors */
3025 _initialize_colors();
3027 /* Determine text cursor alignment from resources */
3029 if (!strcmp(xc_app_data
.textCursor
, "vertical"))
3030 vertical_cursor
= TRUE
;
3032 /* Now have LINES and COLS. Set these in the shared SP so the curses
3033 program can find them. */
3035 LINES
= XCursesLINES
;
3038 if ((shmidSP
= shmget(shmkeySP
, sizeof(SCREEN
) + XCURSESSHMMIN
,
3039 0700 | IPC_CREAT
)) < 0)
3041 perror("Cannot allocate shared memory for SCREEN");
3042 kill(xc_otherpid
, SIGKILL
);
3046 SP
= (SCREEN
*)shmat(shmidSP
, 0, 0);
3047 memset(SP
, 0, sizeof(SCREEN
));
3048 SP
->XcurscrSize
= XCURSCR_SIZE
;
3049 SP
->lines
= XCursesLINES
;
3050 SP
->cols
= XCursesCOLS
;
3052 SP
->mouse_wait
= xc_app_data
.clickPeriod
;
3055 PDC_LOG(("%s:SHM size for curscr %d\n", XCLOGMSG
, SP
->XcurscrSize
));
3057 if ((shmid_Xcurscr
= shmget(shmkey_Xcurscr
, SP
->XcurscrSize
+
3058 XCURSESSHMMIN
, 0700 | IPC_CREAT
)) < 0)
3060 perror("Cannot allocate shared memory for curscr");
3061 kill(xc_otherpid
, SIGKILL
);
3063 shmctl(shmidSP
, IPC_RMID
, 0);
3067 Xcurscr
= (unsigned char *)shmat(shmid_Xcurscr
, 0, 0);
3068 memset(Xcurscr
, 0, SP
->XcurscrSize
);
3069 xc_atrtab
= (short *)(Xcurscr
+ XCURSCR_ATRTAB_OFF
);
3071 PDC_LOG(("%s:shmid_Xcurscr %d shmkey_Xcurscr %d LINES %d COLS %d\n",
3072 XCLOGMSG
, shmid_Xcurscr
, shmkey_Xcurscr
, LINES
, COLS
));
3074 /* Add Event handlers to the drawing widget */
3076 XtAddEventHandler(drawing
, ExposureMask
, False
, _handle_expose
, NULL
);
3077 XtAddEventHandler(drawing
, StructureNotifyMask
, False
,
3078 _handle_structure_notify
, NULL
);
3079 XtAddEventHandler(drawing
, EnterWindowMask
| LeaveWindowMask
, False
,
3080 _handle_enter_leave
, NULL
);
3081 XtAddEventHandler(topLevel
, 0, True
, _handle_nonmaskable
, NULL
);
3083 /* Add input handler from xc_display_sock (requests from curses
3086 XtAppAddInput(app_context
, xc_display_sock
, (XtPointer
)XtInputReadMask
,
3087 _process_curses_requests
, NULL
);
3089 /* If there is a cursorBlink resource, start the Timeout event */
3091 if (xc_app_data
.cursorBlinkRate
)
3092 XtAppAddTimeOut(app_context
, xc_app_data
.cursorBlinkRate
,
3093 _blink_cursor
, NULL
);
3095 /* Leave telling the curses process that it can start to here so
3096 that when the curses process makes a request, the Xcurses
3097 process can service the request. */
3099 XC_write_display_socket_int(CURSES_CHILD
);
3101 XtRealizeWidget(topLevel
);
3103 /* Handle trapping of the WM_DELETE_WINDOW property */
3105 wm_atom
[0] = XInternAtom(XtDisplay(topLevel
), "WM_DELETE_WINDOW", False
);
3107 XSetWMProtocols(XtDisplay(topLevel
), XtWindow(topLevel
), wm_atom
, 1);
3109 /* Create the Graphics Context for drawing. This MUST be done AFTER
3110 the associated widget has been realized. */
3112 XC_LOG(("before _get_gc\n"));
3114 _get_gc(&normal_gc
, xc_app_data
.normalFont
, COLOR_WHITE
, COLOR_BLACK
);
3116 _get_gc(&italic_gc
, italic_font_valid
? xc_app_data
.italicFont
:
3117 xc_app_data
.normalFont
, COLOR_WHITE
, COLOR_BLACK
);
3119 _get_gc(&block_cursor_gc
, xc_app_data
.normalFont
,
3120 COLOR_BLACK
, COLOR_CURSOR
);
3122 _get_gc(&rect_cursor_gc
, xc_app_data
.normalFont
,
3123 COLOR_CURSOR
, COLOR_BLACK
);
3125 _get_gc(&border_gc
, xc_app_data
.normalFont
, COLOR_BORDER
, COLOR_BLACK
);
3127 XSetLineAttributes(XCURSESDISPLAY
, rect_cursor_gc
, 2,
3128 LineSolid
, CapButt
, JoinMiter
);
3130 XSetLineAttributes(XCURSESDISPLAY
, border_gc
, xc_app_data
.borderWidth
,
3131 LineSolid
, CapButt
, JoinMiter
);
3133 /* Set the cursor for the application */
3135 XDefineCursor(XCURSESDISPLAY
, XCURSESWIN
, xc_app_data
.pointer
);
3136 rmfrom
.size
= sizeof(Pixel
);
3137 rmto
.size
= sizeof(XColor
);
3139 rmto
.addr
= (XPointer
)&pointerforecolor
;
3140 rmfrom
.addr
= (XPointer
)&(xc_app_data
.pointerForeColor
);
3141 XtConvertAndStore(drawing
, XtRPixel
, &rmfrom
, XtRColor
, &rmto
);
3143 rmfrom
.size
= sizeof(Pixel
);
3144 rmto
.size
= sizeof(XColor
);
3146 rmfrom
.addr
= (XPointer
)&(xc_app_data
.pointerBackColor
);
3147 rmto
.addr
= (XPointer
)&pointerbackcolor
;
3148 XtConvertAndStore(drawing
, XtRPixel
, &rmfrom
, XtRColor
, &rmto
);
3150 XRecolorCursor(XCURSESDISPLAY
, xc_app_data
.pointer
,
3151 &pointerforecolor
, &pointerbackcolor
);
3155 /* Convert the supplied compose key to a Keysym */
3157 compose_key
= XStringToKeysym(xc_app_data
.composeKey
);
3159 if (compose_key
&& IsModifierKey(compose_key
))
3163 XModifierKeymap
*map
;
3164 KeyCode compose_keycode
= XKeysymToKeycode(XCURSESDISPLAY
, compose_key
);
3166 map
= XGetModifierMapping(XCURSESDISPLAY
);
3167 kcp
= map
->modifiermap
;
3169 for (i
= 0; i
< 8; i
++)
3171 for (j
= 0; j
< map
->max_keypermod
; j
++, kcp
++)
3176 if (compose_keycode
== *kcp
)
3178 compose_mask
= state_mask
[i
];
3187 XFreeModifiermap(map
);
3191 Xim
= XOpenIM(XCURSESDISPLAY
, NULL
, NULL
, NULL
);
3195 Xic
= XCreateIC(Xim
, XNInputStyle
,
3196 XIMPreeditNothing
| XIMStatusNothing
,
3197 XNClientWindow
, XCURSESWIN
, NULL
);
3204 XGetICValues(Xic
, XNFilterEvents
, &im_event_mask
, NULL
);
3206 XtAddEventHandler(drawing
, im_event_mask
, False
,
3207 _dummy_handler
, NULL
);
3213 perror("ERROR: Cannot create input context");
3214 kill(xc_otherpid
, SIGKILL
);
3216 shmdt((char *)Xcurscr
);
3217 shmctl(shmidSP
, IPC_RMID
, 0);
3218 shmctl(shmid_Xcurscr
, IPC_RMID
, 0);
3224 /* Wait for events */
3226 XtAppMainLoop(app_context
);
3227 return OK
; /* won't get here */