diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 02cab5f64..7e0fbc5ab 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1024,30 +1024,30 @@ int CL_LoadModels(int stage, qboolean dontactuallyload) { char *s; qboolean anycsqc; + char *endptr; + unsigned int chksum; #ifdef _DEBUG anycsqc = true; #else anycsqc = atoi(Info_ValueForKey(cl.serverinfo, "anycsqc")); #endif + if (cls.demoplayback) + anycsqc = true; s = Info_ValueForKey(cl.serverinfo, "*csprogs"); - if (anycsqc || *s || cls.demoplayback) //only allow csqc if the server says so, and the 'checksum' matches. + chksum = strtoul(s, &endptr, 0); + if (*endptr) { - char *endptr; - unsigned int chksum = strtoul(s, &endptr, 0); - if (*endptr) - { - Con_Printf("corrupt *csprogs key in serverinfo\n"); - anycsqc = true; - chksum = 0; - } - SCR_SetLoadingFile("csprogs"); - if (!CSQC_Init(anycsqc, chksum)) - { - Sbar_Start(); //try and start this before we're actually on the server, - //this'll stop the mod from sending so much stuffed data at us, whilst we're frozen while trying to load. - //hopefully this'll make it more robust. - //csqc is expected to use it's own huds, or to run on decent servers. :p - } + Con_Printf("corrupt *csprogs key in serverinfo\n"); + anycsqc = true; + chksum = 0; + } + SCR_SetLoadingFile("csprogs"); + if (!CSQC_Init(anycsqc, *s?true:false, chksum)) + { + Sbar_Start(); //try and start this before we're actually on the server, + //this'll stop the mod from sending so much stuffed data at us, whilst we're frozen while trying to load. + //hopefully this'll make it more robust. + //csqc is expected to use it's own huds, or to run on decent servers. :p } endstage(); } @@ -1285,7 +1285,6 @@ Sound_NextDownload */ void Sound_CheckDownloads (void) { - char *s; int i; @@ -1294,6 +1293,7 @@ void Sound_CheckDownloads (void) #ifdef CSQC_DAT // if (cls.fteprotocolextensions & PEXT_CSQC) { + char *s; s = Info_ValueForKey(cl.serverinfo, "*csprogs"); if (*s) //only allow csqc if the server says so, and the 'checksum' matches. { @@ -2843,8 +2843,7 @@ void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caution. #ifdef PEXT_CSQC CSQC_Shutdown(); - if (cls.demoplayback) - CSQC_Init(true, 0); + CSQC_Init(cls.demoplayback, false, 0); #endif } void CLNQ_SignonReply (void) @@ -2881,10 +2880,7 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); { char *s; s = Info_ValueForKey(cl.serverinfo, "*csprogs"); - if (*s) - CSQC_Init(false, atoi(s)); - else - CSQC_Shutdown(); + CSQC_Init(false, *s?true:false, atoi(s)); } #endif } @@ -4786,18 +4782,15 @@ void CL_PrintChat(player_info_t *plr, char *rawmsg, char *msg, int plrflags) if (plrflags & (TPM_TEAM|TPM_OBSERVEDTEAM)) // for team chat don't highlight the name, just the brackets { - // color is reset every printf so we're safe here - Q_strncatz(fullchatmessage, va("\1(%s^%c", name_coloured?"":"^m", c), sizeof(fullchatmessage)); - Q_strncatz(fullchatmessage, va("%s%s^d", name_coloured?"^m":"", name), sizeof(fullchatmessage)); - Q_strncatz(fullchatmessage, va("%s^%c)", name_coloured?"^m":"", c), sizeof(fullchatmessage)); + Q_strncatz(fullchatmessage, va("\1(^[%s%s^d\\player\\%i^])", name_coloured?"^m":"", name, plr-cl.players), sizeof(fullchatmessage)); } else if (cl_standardchat.ival) { - Q_strncatz(fullchatmessage, va("\1%s", name), sizeof(fullchatmessage)); + Q_strncatz(fullchatmessage, va("\1^[%s%s^d\\player\\%i^]", name_coloured?"^m":"", name, plr-cl.players), sizeof(fullchatmessage)); } else { - Q_strncatz(fullchatmessage, va("\1%s^%c%s^d", name_coloured?"":"^m", c, name), sizeof(fullchatmessage)); + Q_strncatz(fullchatmessage, va("\1^[%s^%c%s^d\\player\\%i^]", name_coloured?"^m":"", c, name, plr-cl.players), sizeof(fullchatmessage)); } if (!memessage) @@ -4935,7 +4928,7 @@ void CL_PrintStandardMessage(char *msg, int printlevel) c = '0' + CL_PlayerColor(p, &coloured); // print name - Q_strncatz(fullmessage, va("%s^%c%s^7%s", coloured?"^m":"", c, name, coloured?"^m":""), sizeof(fullmessage)); + Q_strncatz(fullmessage, va("^[%s^%c%s^d\\player\\%i^]", coloured?"^m":"", c, name, p - cl.players), sizeof(fullmessage)); break; } } diff --git a/engine/client/client.h b/engine/client/client.h index e15793116..c6e7e3954 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -1075,7 +1075,8 @@ char *CG_GetConfigString(int num); #ifdef CSQC_DAT qboolean CSQC_Inited(void); void CSQC_RendererRestarted(void); -qboolean CSQC_Init (qboolean anycsqc, unsigned int checksum); +qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum); +qboolean CSQC_ConsoleLink(char *text, char *info); void CSQC_RegisterCvarsAndThings(void); qboolean CSQC_DrawView(void); void CSQC_Shutdown(void); diff --git a/engine/client/console.c b/engine/client/console.c index f6b36f6bb..6191edcfe 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -848,7 +848,7 @@ int Con_DrawInput (int left, int right, int y) text[key_linepos] = 0; cursor = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true); text[key_linepos] = i; - endmtext = COM_ParseFunString(CON_WHITEMASK, text, maskedtext, sizeof(maskedtext) - sizeof(maskedtext[0]), true); + endmtext = COM_ParseFunString(CON_WHITEMASK, text+key_linepos, cursor, ((char*)maskedtext)+sizeof(maskedtext) - (char*)(cursor+1), true); endmtext[1] = 0; @@ -890,11 +890,11 @@ int Con_DrawInput (int left, int right, int y) #endif cursorframe = ((int)(realtime*con_cursorspeed)&1); - for (lhs = 0, i = key_linepos-1; i >= 0; i--) + for (lhs = 0, i = cursor - maskedtext-1; i >= 0; i--) { lhs += Font_CharWidth(maskedtext[i]); } - for (rhs = 0, i = key_linepos+1; maskedtext[i]; i++) + for (rhs = 0, i = cursor - maskedtext; maskedtext[i]; i++) { rhs += Font_CharWidth(maskedtext[i]); } @@ -1575,11 +1575,12 @@ void Con_DrawConsole (int lines, qboolean noback) -char *Con_CopyConsole(void) +char *Con_CopyConsole(qboolean nomarkup) { conchar_t *cur; conline_t *l; conchar_t *lend; + conchar_t col = CON_WHITEMASK; char *result; int outlen, maxlen; int finalendoffset; @@ -1590,6 +1591,9 @@ char *Con_CopyConsole(void) maxlen = 1024*1024; result = Z_Malloc(maxlen+1); +// for (cur = (conchar_t*)(selstartline+1), finalendoffset = 0; cur < (conchar_t*)(selstartline+1) + selstartline->length; cur++, finalendoffset++) +// result[finalendoffset] = *cur & 0xffff; + l = selstartline; cur = (conchar_t*)(l+1) + selstartoffset; finalendoffset = selendoffset; @@ -1603,21 +1607,48 @@ char *Con_CopyConsole(void) while (cur > (conchar_t*)(l+1)) { cur--; - if ((*cur & 0xff) == ' ') + if ((*cur & CON_CHARMASK) == ' ') { cur++; break; } + if (*cur == CON_LINKSTART) + break; } while (finalendoffset < selendline->length) { - if ((((conchar_t*)(l+1))[finalendoffset] & 0xff) != ' ') + if ((((conchar_t*)(l+1))[finalendoffset] & CON_CHARMASK) != ' ') finalendoffset++; else break; } } } + + //scan backwards to find any link enclosure + for(lend = cur; lend >= (conchar_t*)(l+1); lend--) + { + if (*lend == CON_LINKSTART) + { + //found one + cur = lend; + break; + } + if (*lend == CON_LINKEND) + { + //some other link ended here. don't use its start. + break; + } + } + //scan forwards to find the end of the selected link + for(lend = (conchar_t*)(selendline+1) + finalendoffset; lend < (conchar_t*)(selendline+1) + selendline->length; lend++) + { + if (*lend == CON_LINKEND) + { + finalendoffset = lend+1 - (conchar_t*)(selendline+1); + break; + } + } outlen = 0; for (;;) @@ -1626,12 +1657,8 @@ char *Con_CopyConsole(void) lend = (conchar_t*)(l+1) + finalendoffset; else lend = (conchar_t*)(l+1) + l->length; - while (cur < lend) - { - if (outlen == maxlen) - break; - result[outlen++] = *cur++; - } + + outlen = COM_DeFunString(cur, lend, result + outlen, maxlen - outlen, nomarkup) - result; if (l == selendline) break; @@ -1642,6 +1669,9 @@ char *Con_CopyConsole(void) Con_Printf("Error: Bad console buffer\n"); break; } + + if (outlen+3 > maxlen) + break; #ifdef _WIN32 result[outlen++] = '\r'; #endif diff --git a/engine/client/keys.c b/engine/client/keys.c index 1e84cbe44..54dc447b0 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -409,6 +409,12 @@ qboolean Key_GetConsoleSelectionBox(int *sx, int *sy, int *ex, int *ey) con_mousedown[1] -= 8; con_current->display = con_current->display->newer; } + + *sx = mousecursor_x; + *sy = mousecursor_y; + *ex = mousecursor_x; + *ey = mousecursor_y; + return true; } else if (con_mousedown[2] == 2) { @@ -421,16 +427,253 @@ qboolean Key_GetConsoleSelectionBox(int *sx, int *sy, int *ex, int *ey) return false; } +/*insert the given text at the console input line at the current cursor pos*/ +void Key_ConsoleInsert(char *instext) +{ + int i; + int len; + len = strlen(instext); + if (len + strlen(key_lines[edit_line]) > MAXCMDLINE - 1) + len = MAXCMDLINE - 1 - strlen(key_lines[edit_line]); + if (len > 0) + { // insert the string + memmove (key_lines[edit_line] + key_linepos + len, + key_lines[edit_line] + key_linepos, strlen(key_lines[edit_line]) - key_linepos + 1); + memcpy (key_lines[edit_line] + key_linepos, instext, len); + for (i = 0; i < len; i++) + { + if (key_lines[edit_line][key_linepos+i] == '\r') + key_lines[edit_line][key_linepos+i] = ' '; + else if (key_lines[edit_line][key_linepos+i] == '\n') + key_lines[edit_line][key_linepos+i] = ';'; + } + key_linepos += len; + } +} + void Key_ConsoleRelease(int key, int unicode) { + extern int mousecursor_x, mousecursor_y; + char *buffer; if (key == K_MOUSE1) + { con_mousedown[2] = 0; + if (abs(con_mousedown[0] - mousecursor_x) < 5 && abs(con_mousedown[1] - mousecursor_y) < 5) + { + buffer = Con_CopyConsole(false); + if (!buffer) + return; + if (keydown[K_SHIFT]) + { + int len; + len = strlen(buffer); + //strip any trailing dots/elipsis + while (len > 1 && !strcmp(buffer+len-1, ".")) + { + len-=1; + buffer[len] = 0; + } + //strip any enclosing quotes + while (*buffer == '\"' && len > 2 && !strcmp(buffer+len-1, "\"")) + { + len-=2; + memmove(buffer, buffer+1, len); + buffer[len] = 0; + } + Key_ConsoleInsert(buffer); + } + else + { + if (buffer[0] == '^' && buffer[1] == '[') + { + //looks like it might be a link! + char *end = NULL; + char *info; + for (info = buffer + 2; *info; ) + { + if (info[0] == '^' && info[1] == ']') + { + break; + } + if (*info == '\\') + break; + else if (info[0] == '^' && info[1] == '^') + info+=2; + else + info++; + } + for(end = info; *end; ) + { + if (end[0] == '^' && end[1] == ']') + { + char *c; + //okay, its a valid link that they clicked + *end = 0; +#ifdef CSQC_DAT + if (!CSQC_ConsoleLink(buffer+2, info)) +#endif + { + /*the engine supports specific default links*/ + /*we don't support everything. a: there's no point. b: unbindall links are evil.*/ + c = Info_ValueForKey(info, "player"); + if (*c) + { + unsigned int player = atoi(c); + int i; + if (player >= MAX_CLIENTS) + break; + + c = Info_ValueForKey(info, "action"); + if (*c) + { + if (!strcmp(c, "mute")) + { + if (!cl.players[player].vignored) + { + cl.players[player].vignored = true; + Con_Printf("^[%s\\player\\%i^] muted\n", cl.players[player].name, player); + } + else + { + cl.players[player].vignored = false; + Con_Printf("^[%s\\player\\%i^] unmuted\n", cl.players[player].name, player); + } + } + else if (!strcmp(c, "ignore")) + { + if (!cl.players[player].ignored) + { + cl.players[player].ignored = true; + cl.players[player].vignored = true; + Con_Printf("^[%s\\player\\%i^] ignored\n", cl.players[player].name, player); + } + else + { + cl.players[player].ignored = false; + cl.players[player].vignored = false; + Con_Printf("^[%s\\player\\%i^] unignored\n", cl.players[player].name, player); + } + } + else if (!strcmp(c, "kick")) + { +#ifndef CLIENTONLY + if (sv.active) + { + //use the q3 command, because we can. + Cbuf_AddText(va("\nclientkick %i\n", player), RESTRICT_LOCAL); + } + else +#endif + Cbuf_AddText(va("\nrcon kick %s\n", cl.players[player].name), RESTRICT_LOCAL); + } + else if (!strcmp(c, "ban")) + { +#ifndef CLIENTONLY + if (sv.active) + { + //use the q3 command, because we can. + Cbuf_AddText(va("\nbanname %s QuickBan\n", cl.players[player].name), RESTRICT_LOCAL); + } + else +#endif + Cbuf_AddText(va("\nrcon banname %s QuickBan\n", cl.players[player].name), RESTRICT_LOCAL); + } + break; + } + + Con_Printf("^m#^m ^[%s\\player\\%i^]: %if %ims", cl.players[player].name, player, cl.players[player].frags, cl.players[player].ping); + + for (i = 0; i < cl.splitclients; i++) + { + if (cl.playernum[i] == player) + break; + } + if (i == cl.splitclients) + { + extern cvar_t rcon_password; + if (cls.protocol == CP_QUAKEWORLD && strcmp(cl.players[cl.playernum[0]].team, cl.players[player].team)) + Con_Printf(" ^[[Join Team %s]\\cmd\\setinfo team %s^]", cl.players[player].team, cl.players[player].team); + Con_Printf(" ^[%sgnore\\player\\%i\\action\\ignore^]", cl.players[player].ignored?"Uni":"I", player); +// if (cl_voip_play.ival) + Con_Printf(" ^[%sute\\player\\%i\\action\\mute^]", cl.players[player].vignored?"Unm":"M", player); + + if (*rcon_password.string +#ifndef CLIENTONLY + || (sv.state && svs.clients[player].netchan.remote_address.type != NA_LOOPBACK) +#endif + ) + { + Con_Printf(" ^[Kick\\player\\%i\\action\\kick^]", player); + Con_Printf(" ^[Ban\\player\\%i\\action\\ban^]", player); + } + } + else + { + char cmdprefix[6]; + snprintf(cmdprefix, sizeof(cmdprefix), "%i ", i); + + //hey look! its you! + Con_Printf(" ^[Suicide\\cmd\\kill^]"); +#ifndef CLIENTONLY + if (!sv.state) + Con_Printf(" ^[Disconnect\\cmd\\disconnect^]"); + if (cls.allow_cheats || (sv.state && sv.allocated_client_slots == 1)) +#else + Con_Printf(" ^[Disconnect\\cmd\\disconnect^]"); + if (cls.allow_cheats) +#endif + { + Con_Printf(" ^[Noclip\\cmd\\noclip^]"); + Con_Printf(" ^[Fly\\cmd\\fly^]"); + Con_Printf(" ^[God\\cmd\\god^]"); + Con_Printf(" ^[Give\\impulse\\9^]"); + } + } + Con_Printf("\r"); + break; + } + c = Info_ValueForKey(info, "connect"); + if (*c && !strchr(c, ';') && !strchr(c, '\n')) + { + Cbuf_AddText(va("\nconnect %s\n", c), RESTRICT_LOCAL); + break; + } + c = Info_ValueForKey(info, "qtv"); + if (*c && !strchr(c, ';') && !strchr(c, '\n')) + { + Cbuf_AddText(va("\nqtvplay %s\n", c), RESTRICT_LOCAL); + break; + } + c = Info_ValueForKey(info, "cmd"); + if (*c && !strchr(c, ';') && !strchr(c, '\n')) + { + Cbuf_AddText(va("\ncmd %s\n", c), RESTRICT_LOCAL); + break; + } + c = Info_ValueForKey(info, "impulse"); + if (*c && !strchr(c, ';') && !strchr(c, '\n')) + { + Cbuf_AddText(va("\nimpulse %s\n", c), RESTRICT_LOCAL); + break; + } + } + + break; + } + if (end[0] == '^' && end[1] == '^') + end+=2; + else + end++; + } + } + } + Z_Free(buffer); + } + } if (key == K_MOUSE2 && con_mousedown[2] == 2) { - extern int mousecursor_x, mousecursor_y; - char *buffer; con_mousedown[2] = 0; - buffer = Con_CopyConsole(); + buffer = Con_CopyConsole(true); //don't keep markup if we're copying to the clipboard if (!buffer) return; Sys_SaveClipboard(buffer); @@ -439,6 +682,91 @@ void Key_ConsoleRelease(int key, int unicode) } } +//move the cursor one char to the left. cursor must be within the 'start' string. +unsigned char *utf_left(unsigned char *start, unsigned char *cursor) +{ + extern cvar_t com_parseutf8; + if (cursor == start) + return cursor; + if (com_parseutf8.ival>0) + { + cursor--; + while ((*cursor & 0xc0) == 0x80 && cursor > start) + cursor--; + } + else + cursor--; + + if (*cursor == ']' && cursor > start && cursor[-1] == '^') + { + //just stepped onto a link + char *linkstart; + linkstart = cursor-1; + while(linkstart >= start) + { + if (linkstart[0] == '^' && linkstart[1] == '[') + return linkstart; + linkstart--; + } + } + + return cursor; +} + +//move the cursor one char to the right. +unsigned char *utf_right(unsigned char *cursor) +{ + extern cvar_t com_parseutf8; + + if (*cursor == '^' && cursor[1] == '[') + { + //just stepped over a link + char *linkend; + linkend = cursor+2; + while(*linkend) + { + if (linkend[0] == '^' && linkend[1] == '^') + linkend += 2; + else if (linkend[0] == '^' && linkend[1] == ']') + return linkend+2; + else + linkend++; + } + return linkend; + } + + if (com_parseutf8.ival>0) + { + int skip = 1; + //figure out the length of the char + if ((*cursor & 0xc0) == 0x80) + skip = 1; //error + else if ((*cursor & 0xe0) == 0xc0) + skip = 2; + else if ((*cursor & 0xf0) == 0xe0) + skip = 3; + else if ((*cursor & 0xf1) == 0xf0) + skip = 4; + else if ((*cursor & 0xf3) == 0xf1) + skip = 5; + else if ((*cursor & 0xf7) == 0xf3) + skip = 6; + else if ((*cursor & 0xff) == 0xf7) + skip = 7; + else skip = 1; + + while (*cursor && skip) + { + cursor++; + skip--; + } + } + else if (*cursor) + cursor++; + + return cursor; +} + /* ==================== Key_Console @@ -544,15 +872,14 @@ void Key_Console (unsigned int unicode, int key) if (key == K_LEFTARROW) { - if (key_linepos > 1) - key_linepos--; + key_linepos = utf_left(key_lines[edit_line]+1, key_lines[edit_line] + key_linepos) - key_lines[edit_line]; return; } if (key == K_RIGHTARROW) { if (key_lines[edit_line][key_linepos]) { - key_linepos++; + key_linepos = utf_right(key_lines[edit_line] + key_linepos) - key_lines[edit_line]; return; } else @@ -563,15 +890,8 @@ void Key_Console (unsigned int unicode, int key) { if (key_lines[edit_line][key_linepos]) { - int charlen = 1; - if (com_parseutf8.ival>0 && - (key_lines[edit_line][key_linepos] & 0xc0) != 0x80) - { - while((key_lines[edit_line][key_linepos+charlen] & 0xc0) == 0x80) - charlen++; - } - - memmove(key_lines[edit_line]+key_linepos, key_lines[edit_line]+key_linepos+charlen, strlen(key_lines[edit_line]+key_linepos+charlen)+charlen); + int charlen = utf_right(key_lines[edit_line] + key_linepos) - (key_lines[edit_line] + key_linepos); + memmove(key_lines[edit_line]+key_linepos, key_lines[edit_line]+key_linepos+charlen, strlen(key_lines[edit_line]+key_linepos+charlen)+1); return; } else @@ -582,13 +902,8 @@ void Key_Console (unsigned int unicode, int key) { if (key_linepos > 1) { - int charlen = 1; - if (com_parseutf8.ival>0) - { - while (key_linepos > charlen && (key_lines[edit_line][key_linepos-charlen] & 0xc0) == 0x80) - charlen++; - } - memmove(key_lines[edit_line]+key_linepos-charlen, key_lines[edit_line]+key_linepos, strlen(key_lines[edit_line]+key_linepos)+charlen); + int charlen = (key_lines[edit_line]+key_linepos) - utf_left(key_lines[edit_line]+1, key_lines[edit_line] + key_linepos); + memmove(key_lines[edit_line]+key_linepos-charlen, key_lines[edit_line]+key_linepos, strlen(key_lines[edit_line]+key_linepos)+1); key_linepos -= charlen; } return; @@ -692,36 +1007,19 @@ void Key_Console (unsigned int unicode, int key) return; } - if (((unicode=='C' || unicode=='c') && keydown[K_CTRL]) || (keydown[K_CTRL] && key == K_INS)) + //beware that windows translates ctrl+c and ctrl+v to a control char + if (((unicode=='C' || unicode=='c' || unicode==3) && keydown[K_CTRL]) || (keydown[K_CTRL] && key == K_INS)) { Sys_SaveClipboard(key_lines[edit_line]+1); return; } - if (((unicode=='V' || unicode=='v') && keydown[K_CTRL]) || (keydown[K_SHIFT] && key == K_INS)) + if (((unicode=='V' || unicode=='v' || unicode==22) && keydown[K_CTRL]) || (keydown[K_SHIFT] && key == K_INS)) { clipText = Sys_GetClipboard(); if (clipText) { - int i; - int len; - len = strlen(clipText); - if (len + strlen(key_lines[edit_line]) > MAXCMDLINE - 1) - len = MAXCMDLINE - 1 - strlen(key_lines[edit_line]); - if (len > 0) - { // insert the string - memmove (key_lines[edit_line] + key_linepos + len, - key_lines[edit_line] + key_linepos, strlen(key_lines[edit_line]) - key_linepos + 1); - memcpy (key_lines[edit_line] + key_linepos, clipText, len); - for (i = 0; i < len; i++) - { - if (key_lines[edit_line][key_linepos+i] == '\r') - key_lines[edit_line][key_linepos+i] = ' '; - else if (key_lines[edit_line][key_linepos+i] == '\n') - key_lines[edit_line][key_linepos+i] = ';'; - } - key_linepos += len; - } + Key_ConsoleInsert(clipText); Sys_CloseClipboard(clipText); } return; @@ -1466,7 +1764,7 @@ void Key_Event (int devid, int key, unsigned int unicode, qboolean down) //yes, csqc is allowed to steal the escape key. if (key != '`' && key != '~') - if (key_dest == key_game) + if (key_dest == key_game && !Media_PlayingFullScreen()) { #ifdef CSQC_DAT if (CSQC_KeyPress(key, unicode, down, devid)) //give csqc a chance to handle it. diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 44720d569..0fe7bb489 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -2199,6 +2199,8 @@ qboolean Media_PlayFilm(char *name) cin->ended = false; if (cin->rewind) cin->rewind(cin); + if (cin->changestream) + cin->changestream(cin, "cmd:focus"); } else { diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 48aab5844..95239219f 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -107,6 +107,7 @@ extern sfx_t *cl_sfx_r_exp3; globalfunction(input_event, "CSQC_InputEvent"); \ globalfunction(input_frame, "CSQC_Input_Frame");/*EXT_CSQC_1*/ \ globalfunction(console_command, "CSQC_ConsoleCommand"); \ + globalfunction(console_link, "CSQC_ConsoleLink"); \ globalfunction(gamecommand, "GameCommand"); /*DP extension*/\ \ globalfunction(ent_update, "CSQC_Ent_Update"); \ @@ -1251,6 +1252,15 @@ static void QCBUILTIN PF_R_GetViewFlag(progfuncs_t *prinst, struct globalvars_s *r = r_refdef.useperspective; break; + case VF_SCREENVSIZE: + r[0] = vid.width; + r[1] = vid.height; + break; + case VF_SCREENPSIZE: + r[0] = vid.rotpixelwidth; + r[1] = vid.rotpixelheight; + break; + default: Con_DPrintf("GetViewFlag: %i not recognised\n", parametertype); break; @@ -4947,7 +4957,7 @@ qboolean CSQC_Inited(void) } double csqctime; -qboolean CSQC_Init (qboolean anycsqc, unsigned int checksum) +qboolean CSQC_Init (qboolean anycsqc, qboolean csdatenabled, unsigned int checksum) { int i; string_t *str; @@ -5054,23 +5064,27 @@ qboolean CSQC_Init (qboolean anycsqc, unsigned int checksum) } csqc_isdarkplaces = false; - if (PR_LoadProgs(csqcprogs, "csprogs.dat", 22390, NULL, 0) >= 0) - loaded = true; - else + if (csdatenabled || csqc_singlecheats || anycsqc) { - if (PR_LoadProgs(csqcprogs, "csprogs.dat", 52195, NULL, 0) >= 0) - loaded = true; - else if (PR_LoadProgs(csqcprogs, "csprogs.dat", 0, NULL, 0) >= 0) + if (PR_LoadProgs(csqcprogs, "csprogs.dat", 22390, NULL, 0) >= 0) loaded = true; else - loaded = false; + { + if (PR_LoadProgs(csqcprogs, "csprogs.dat", 52195, NULL, 0) >= 0) + loaded = true; + else if (PR_LoadProgs(csqcprogs, "csprogs.dat", 0, NULL, 0) >= 0) + loaded = true; + else + loaded = false; - if (loaded) - Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n"); + if (loaded) + Con_Printf(CON_WARNING "Running outdated or unknown csprogs.dat version\n"); + } } - if (csqc_singlecheats) + if (csqc_singlecheats || anycsqc) { + Con_DPrintf("loading csaddon.dat...\n"); if (PR_LoadProgs(csqcprogs, "csaddon.dat", 0, NULL, 0) >= 0) loaded = true; } @@ -5518,6 +5532,21 @@ qboolean CSQC_Accelerometer(float x, float y, float z) return G_FLOAT(OFS_RETURN); } +qboolean CSQC_ConsoleLink(char *text, char *info) +{ + void *pr_globals; + if (!csqcprogs || !csqcg.console_link) + return false; + + pr_globals = PR_globals(csqcprogs, PR_CURRENT); + (((string_t *)pr_globals)[OFS_PARM1] = PR_TempString(csqcprogs, info)); + *info = 0; + (((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, text)); + *info = '\\'; + PR_ExecuteProgram (csqcprogs, csqcg.console_link); + return G_FLOAT(OFS_RETURN); +} + qboolean CSQC_ConsoleCommand(char *cmd) { void *pr_globals; diff --git a/engine/common/common.c b/engine/common/common.c index a452e9a09..7f4aeb185 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1863,31 +1863,74 @@ conchar_t q3codemasks[MAXQ3COLOURS] = { 0x07000000 // 9, "half-intensity" (BX_COLOREDTEXT) }; - -//Strips out the flags -void COM_DeFunString(conchar_t *str, char *out, int outsize, qboolean ignoreflags) +//Converts a conchar_t string into a char string. returns the null terminator. pass NULL for stop to calc it +char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags) { - if (ignoreflags) + if (!stop) { - while(*str) + for (stop = str; *stop; stop++) + ; + } +#ifdef _DEBUG + if (!outsize) + Sys_Error("COM_DeFunString given outsize=0"); +#endif + + /*if (ignoreflags) + { + while(str < stop) { if (!--outsize) break; *out++ = (unsigned char)(*str++&255); } - *out++ = 0; + *out = 0; } - else + else*/ { int fl, d; + unsigned int c; + int prelinkflags = CON_WHITEMASK; //if used, its already an error. //FIXME: TEST! fl = CON_WHITEMASK; - while(*str) + while(str < stop) { - if (!--outsize) - break; - if ((*str & CON_FLAGSMASK) != fl) + if ((*str & CON_HIDDEN) && ignoreflags) + { + str++; + continue; + } + if (*str == CON_LINKSTART) + { + if (!ignoreflags) + { + if (outsize<=2) + break; + outsize -= 2; + *out++ = '^'; + *out++ = '['; + } + prelinkflags = fl; + fl = COLOR_RED << CON_FGSHIFT; + str++; + continue; + } + else if (*str == CON_LINKEND) + { + if (!ignoreflags) + { + if (outsize<=2) + break; + outsize -= 2; + *out++ = '^'; + *out++ = ']'; + } + fl = prelinkflags; + str++; + continue; + } + else if ((*str & CON_FLAGSMASK) != fl && !ignoreflags) { d = fl^(*str & CON_FLAGSMASK); // if (fl & CON_NONCLEARBG) //not represented. @@ -1918,31 +1961,130 @@ void COM_DeFunString(conchar_t *str, char *out, int outsize, qboolean ignoreflag if (d & (CON_FGMASK | CON_BGMASK | CON_NONCLEARBG)) { - if (outsize<=4) - break; - outsize -= 4; - - d = (*str & CON_FLAGSMASK); - *out++ = '^'; - *out++ = '&'; - if ((d & CON_FGMASK) == CON_WHITEMASK) - *out++ = '-'; - else - sprintf(out, "%X", d>>24); - if (d & CON_NONCLEARBG) + static char q3[16] = { '0', 0, 0, 0, + 0, 0, 0, 0, + 0, '4', '2', '5', + '1', '6', '3', '7'}; + if (!(d & (CON_BGMASK | CON_NONCLEARBG)) && q3[(*str & CON_FGMASK) >> CON_FGSHIFT] && !((d|fl) & CON_HALFALPHA)) { - sprintf(out, "%X", d>>28); + if (outsize<=2) + break; + outsize -= 2; + + d = (*str & CON_FLAGSMASK); + *out++ = '^'; + *out++ = q3[(*str & CON_FGMASK) >> CON_FGSHIFT]; } else - *out++ = '-'; + { + if (outsize<=4) + break; + outsize -= 4; + + d = (*str & CON_FLAGSMASK); + *out++ = '^'; + *out++ = '&'; + if ((d & CON_FGMASK) == CON_WHITEMASK) + *out = '-'; + else + sprintf(out, "%X", d>>24); + out++; + if (d & CON_NONCLEARBG) + sprintf(out, "%X", d>>28); + else + *out = '-'; + out++; + } } fl = (*str & CON_FLAGSMASK); } - *out++ = (unsigned char)(*str++&255); + + //don't magically show hidden text + if (ignoreflags && (*str & CON_HIDDEN)) + continue; + + c = *str++ & 0xffff; + if (com_parseutf8.ival > 0) + { + //utf-8 + if (c > 0x7ff) + { + if (outsize<=3) + break; + outsize -= 3; + + *out++ = (unsigned char)((c>>12)&0x0f) | 0xe0; + *out++ = (unsigned char)((c>>6)&0x3f) | 0x80; + *out++ = (unsigned char)(c&0x3f) | 0x80; + } + else if (c > 0x7f) + { + if (outsize<=2) + break; + outsize -= 2; + + *out++ = (unsigned char)((c>>6)&0x1f) | 0xc0; + *out++ = (unsigned char)(c&0x3f) | 0x80; + } + else + { + if (outsize<=1) + break; + outsize -= 1; + *out++ = (unsigned char)(c&0x7f); + } + } + else if (com_parseutf8.ival) + { + //iso8859-1 + if ((c >= 0 && c < 255) || (c >= 0xe000+32 && c < 0xe000+127)) //quake chars between 32 and 127 are identical to iso8859-1 + { + if (!--outsize) + break; + *out++ = (unsigned char)(c&255); + } + else //any other quake char is not iso8859-1 + { + const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if (outsize<=6) + break; + outsize -= 6; + *out++ = '^'; + *out++ = 'U'; + *out++ = hex[(c>>12)&15]; + *out++ = hex[(c>>8)&15]; + *out++ = hex[(c>>4)&15]; + *out++ = hex[(c>>0)&15]; + } + } + else + { + //quake chars + if (c == '\n' || c == '\r' || c == '\t' || (c >= 32 && c < 127) || (c >= 0xe000 && c < 0xe100)) //quake chars between 32 and 127 are identical to iso8859-1 + { + if (!--outsize) + break; + *out++ = (unsigned char)(c&255); + } + else //any other char is not quake + { + const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if (outsize<=6) + break; + outsize -= 6; + *out++ = '^'; + *out++ = 'U'; + *out++ = hex[(c>>12)&15]; + *out++ = hex[(c>>8)&15]; + *out++ = hex[(c>>4)&15]; + *out++ = hex[(c>>0)&15]; + } + } } - *out++ = 0; + *out = 0; } + return out; } static int dehex(int i) @@ -1963,6 +2105,9 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t int extstackdepth = 0; unsigned int uc, l; int utf8 = com_parseutf8.ival; + conchar_t linkinitflags = CON_WHITEMASK;/*doesn't need the init, but msvc is stupid*/ + qboolean linkkeep = keepmarkup; + conchar_t *linkstart = NULL; conchar_t ext; @@ -2120,6 +2265,40 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t // else invalid code goto messedup; } + else if (str[1] == '[' && !linkstart) + { + //preserved flags and reset to white. links must contain their own colours. + linkinitflags = ext; + ext = COLOR_RED << CON_FGSHIFT; + linkstart = out; + *out++ = '['; + + //never keep the markup + linkkeep = keepmarkup; + keepmarkup = false; + str+=2; + continue; + } + else if (str[1] == ']' && linkstart) + { + *out++ = ']'; + + //its a valid link, so we can hide it all now + *linkstart++ |= CON_HIDDEN; //leading [ is hidden + while(linkstart < out-1 && (*linkstart&CON_CHARMASK) != '\\') //link text is NOT hidden + linkstart++; + while(linkstart < out) //but the infostring behind it is, as well as the terminator + *linkstart++ |= CON_HIDDEN; + + //reset colours to how they used to be + ext = linkinitflags; + linkstart = NULL; + keepmarkup = linkkeep; + + //never keep the markup + str+=2; + continue; + } else if (str[1] == 'a') { ext ^= CON_2NDCHARSETTEXT; @@ -2130,7 +2309,10 @@ conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t } else if (str[1] == 'd') { - ext = defaultflags; + if (linkstart) + ext = COLOR_RED << CON_FGSHIFT; + else + ext = defaultflags; } else if (str[1] == 'm') { diff --git a/engine/common/common.h b/engine/common/common.h index a59fb9722..cf76ac64e 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -275,7 +275,7 @@ void COM_InitArgv (int argc, const char **argv); void COM_ParsePlusSets (void); typedef unsigned int conchar_t; -void COM_DeFunString(conchar_t *str, char *out, int outsize, qboolean ignoreflags); +char *COM_DeFunString(conchar_t *str, conchar_t *stop, char *out, int outsize, qboolean ignoreflags); conchar_t *COM_ParseFunString(conchar_t defaultflags, const char *str, conchar_t *out, int outsize, qboolean keepmarkup); //ext is usually CON_WHITEMASK, returns its null terminator int COM_FunStringLength(unsigned char *str); diff --git a/engine/common/console.h b/engine/common/console.h index 63a93d6df..ff5e00650 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -38,7 +38,7 @@ extern conchar_t q3codemasks[MAXQ3COLOURS]; #define CON_HIGHCHARSMASK 0x00000080 // Quake's alternative mask #define CON_FLAGSMASK 0xFFF00000 -#define CON_UNUSEDMASK 0x000F0000 +#define CON_HIDDEN 0x000F0000 #define CON_CHARMASK 0x0000FFFF #define CON_FGMASK 0x0F000000 @@ -51,6 +51,9 @@ extern conchar_t q3codemasks[MAXQ3COLOURS]; #define CON_DEFAULTCHAR (CON_WHITEMASK | 32) +#define CON_LINKSTART (CON_HIDDEN | '[') +#define CON_LINKEND (CON_HIDDEN | ']') + // RGBI standard colors #define COLOR_BLACK 0 #define COLOR_DARKBLUE 1 @@ -142,7 +145,7 @@ void Con_ForceActiveNow(void); void Con_Init (void); void Con_Shutdown (void); void Con_DrawConsole (int lines, qboolean noback); -char *Con_CopyConsole(void); +char *Con_CopyConsole(qboolean nomarkup); void Con_Print (char *txt); void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1); void VARGS Con_TPrintf (translation_t text, ...); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index ee6308e83..e1e7b98f2 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -5846,7 +5846,7 @@ int CM_WriteAreaBits (model_t *mod, qbyte *buffer, int area) return bytes; } - +#ifndef CLIENTONLY void CM_InitPortalState(void) { int i; @@ -5857,6 +5857,7 @@ void CM_InitPortalState(void) map_q2areas[i].floodnum = 0; } } +#endif /* =================== diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 23894d075..ed784680d 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -2290,7 +2290,7 @@ void QCBUILTIN PF_strdecolorize (progfuncs_t *prinst, struct globalvars_s *pr_gl char result[8192]; unsigned int flagged[8192]; COM_ParseFunString(CON_WHITEMASK, in, flagged, sizeof(flagged), false); - COM_DeFunString(flagged, result, sizeof(result), true); + COM_DeFunString(flagged, NULL, result, sizeof(result), true); RETURN_TSTRING(result); } diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 9c7df50b9..fc4075abf 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -435,6 +435,8 @@ typedef enum //201 used by DP... WTF? CLEARSCREEN VF_LPLAYER = 202, VF_AFOV = 203, //aproximate fov (match what the engine would normally use for the fov cvar). p0=fov, p1=zoom + VF_SCREENVSIZE = 204, + VF_SCREENPSIZE = 205, } viewflags; /*FIXME: this should be changed*/ diff --git a/engine/d3d/d3d11_shader.c b/engine/d3d/d3d11_shader.c index 16135eeda..684e9dd05 100644 --- a/engine/d3d/d3d11_shader.c +++ b/engine/d3d/d3d11_shader.c @@ -338,4 +338,5 @@ int D3D11Shader_FindUniform(union programhandle_u *h, int type, char *name) #endif return -1; } -#endif \ No newline at end of file +#endif + diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 2cf38da12..f658a7a73 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -9,11 +9,6 @@ #define COBJMACROS #include <d3d11.h> -//#include <d3d9.h> - -//#pragma comment(lib, "../libs/dxsdk9/lib/d3d9.lib") - - /*Fixup outdated windows headers*/ #ifndef WM_XBUTTONDOWN #define WM_XBUTTONDOWN 0x020B diff --git a/engine/dotnet2005/npfte.vcproj b/engine/dotnet2005/npfte.vcproj index 3c177f0a4..ca2d9d3a9 100644 --- a/engine/dotnet2005/npfte.vcproj +++ b/engine/dotnet2005/npfte.vcproj @@ -22538,6 +22538,18 @@ /> </FileConfiguration> </File> + <File + RelativePath="..\common\sha1.c" + > + <FileConfiguration + Name="GLDebug|Win32" + > + <Tool + Name="VCCLCompilerTool" + UsePrecompiledHeader="0" + /> + </FileConfiguration> + </File> <File RelativePath="..\common\translate.c" > diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index a12626123..508ef5b61 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -3213,11 +3213,11 @@ void GLBE_SelectDLight(dlight_t *dl, vec3_t colour) shaderstate.lastuniform = 0; lmode = 0; - if (dl->fov && shaderstate.shader_light[lmode|LSHADER_SPOT]->prog) + if (dl->fov && shaderstate.shader_light[lmode|LSHADER_SPOT] && shaderstate.shader_light[lmode|LSHADER_SPOT]->prog) lmode |= LSHADER_SPOT; - if ((dl->flags & LFLAG_SHADOWMAP) && shaderstate.shader_light[lmode|LSHADER_SMAP]->prog) + if ((dl->flags & LFLAG_SHADOWMAP) && shaderstate.shader_light[lmode|LSHADER_SMAP] && shaderstate.shader_light[lmode|LSHADER_SMAP]->prog) lmode |= LSHADER_SMAP; - if (TEXVALID(shaderstate.lightcubemap) && shaderstate.shader_light[lmode|LSHADER_CUBE]->prog) + if (TEXVALID(shaderstate.lightcubemap) && shaderstate.shader_light[lmode|LSHADER_CUBE] && shaderstate.shader_light[lmode|LSHADER_CUBE]->prog) lmode |= LSHADER_CUBE; shaderstate.lightmode = lmode; } diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index b25b6f322..24d6b2a05 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1190,6 +1190,8 @@ int Font_CharEndCoord(struct font_s *font, int x, unsigned int charcode) { struct charcache_s *c; #define TABWIDTH (8*20) + if (charcode&CON_HIDDEN) + return x; if ((charcode&CON_CHARMASK) == '\t') return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH); @@ -1212,6 +1214,8 @@ int Font_CharWidth(unsigned int charcode) { struct charcache_s *c; struct font_s *font = curfont; + if (charcode&CON_HIDDEN) + return 0; if ((charcode & CON_2NDCHARSETTEXT) && font->alt) font = font->alt; @@ -1333,6 +1337,9 @@ int Font_DrawChar(int px, int py, unsigned int charcode) int col; int v; struct font_s *font = curfont; + if (charcode & CON_HIDDEN) + return px; + if ((charcode & CON_2NDCHARSETTEXT) && font->alt) font = font->alt; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 3d8200ded..194e66f7c 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9946,6 +9946,8 @@ void PR_DumpPlatform_f(void) {"VF_PERSPECTIVE", "const float", CS, VF_PERSPECTIVE}, {"VF_LPLAYER", "const float", CS, VF_LPLAYER}, {"VF_AFOV", "const float", CS, VF_AFOV}, + {"VF_SCREENVSIZE", "const float", CS, VF_SCREENVSIZE}, + {"VF_SCREENPSIZE", "const float", CS, VF_SCREENPSIZE}, {"RF_VIEWMODEL", "const float", CS, CSQCRF_VIEWMODEL}, {"RF_EXTERNALMODEL", "const float", CS, CSQCRF_EXTERNALMODEL}, diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 0bbfb0f55..93cd76f15 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -4523,6 +4523,7 @@ void SV_FixupName(char *in, char *out, unsigned int outlen) { char *s, *p; unsigned int len; + conchar_t testbuf[1024], *t, *e; if (outlen == 0) return; @@ -4544,7 +4545,20 @@ void SV_FixupName(char *in, char *out, unsigned int outlen) } *s = '\0'; - if (!*out) + /*note: clients are not guarenteed to parse things the same as the server. utf-8 surrogates may be awkward here*/ + e = COM_ParseFunString(CON_WHITEMASK, out, testbuf, sizeof(testbuf), false); + for (t = testbuf; t < e; t++) + { + /*reject anything hidden in names*/ + if (*t & CON_HIDDEN) + break; + /*reject pictograms*/ + if ((*t & CON_CHARMASK) >= 0xe100 && (*t & CON_CHARMASK) < 0xe200) + break; + /*FIXME: should we try to ensure that the chars are in most fonts? that might annoy speakers of more exotic languages I suppose. cvar it?*/ + } + + if (!*out || (t < e) || e == testbuf) { //reached end and it was all whitespace //white space only strncpy(out, "unnamed", outlen); diff --git a/plugins/berkelium/plugapi.cpp b/plugins/berkelium/plugapi.cpp index 805cfef92..2d7de18d5 100644 --- a/plugins/berkelium/plugapi.cpp +++ b/plugins/berkelium/plugapi.cpp @@ -23,40 +23,105 @@ class MyDelegate : public Berkelium::WindowDelegate private: decctx *ctx; + virtual void onCrashedWorker(Berkelium::Window *win) + { + int i; + Con_Printf("Berkelium worker crashed\n"); + + /*black it out*/ + for (i = 0; i < ctx->width*ctx->height; i++) + { + ctx->buffer[i] = 0xff000000; + } + ctx->repainted = true; + } + + virtual void onCrashed(Berkelium::Window *win) + { + int i; + Con_Printf("Berkelium window crashed\n"); + + /*black it out*/ + for (i = 0; i < ctx->width*ctx->height; i++) + { + ctx->buffer[i] = 0xff000000; + } + ctx->repainted = true; + } + virtual void onUnresponsive(Berkelium::Window *win) + { + Con_Printf("Berkelium window unresponsive\n"); + } + virtual void onResponsive(Berkelium::Window *win) + { + Con_Printf("Berkelium window responsive again, yay\n"); + } + virtual void onPaint(Berkelium::Window *wini, const unsigned char *bitmap_in, const Berkelium::Rect &bitmap_rect, size_t num_copy_rects, const Berkelium::Rect *copy_rects, int dx, int dy, const Berkelium::Rect& scroll_rect) { int i; // handle paint events... if (dx || dy) { - int y; - int t = scroll_rect.top(); - int l = scroll_rect.left(); + int y, m; + int dt = scroll_rect.top(); + int dl = scroll_rect.left(); int w = scroll_rect.width(); int h = scroll_rect.height(); - if (dy > 0) - { - //if we're moving downwards, we need to write the bottom before the top (so we don't overwrite the data before its copied) - for (y = t+h-1; y >= t; y--) - { - if (y < 0 || y >= ctx->height) - continue; - if (y+dy < 0 || y+dy >= ctx->height) - continue; - memmove(ctx->buffer + ((l+dx) + (y+dy)*ctx->width), ctx->buffer + (l + y*ctx->width), w*4); - } - } - else - { - //moving upwards requires we write the top row first - for (y = t; y < t+h; y++) - { - if (y < 0 || y >= ctx->height) - continue; - if (y+dy < 0 || y+dy >= ctx->height) - continue; + int st = dt - dy; + int sl = dl - dx; - memmove(ctx->buffer + ((l+dx) + (y+dy)*ctx->width), ctx->buffer + (l + y*ctx->width), w*4); + /*bound the output rect*/ + if (dt < 0) + { + st -= dt; + h += dt; + dt = 0; + } + if (dl < 0) + { + sl -= dl; + w += dl; + dl = 0; + } + /*bound the source rect*/ + if (st < 0) + { + dt -= st; + h += st; + st = 0; + } + if (sl < 0) + { + dl -= sl; + w += sl; + sl = 0; + } + /*bound the width*/ + m = (dl>sl)?dl:sl; + if (m + w > ctx->width) + w = ctx->width - m; + m = (dt>st)?dt:st; + if (m + h > ctx->height) + h = ctx->height - m; + + if (w > 0 && h > 0) + { + if (dy > 0) + { + //if we're moving downwards, we need to write the bottom before the top (so we don't overwrite the data before its copied) + for (y = h; y >= 0; y--) + { + memmove(ctx->buffer + (dl + (dt+y)*ctx->width), ctx->buffer + (sl + (st+y)*ctx->width), w*4); + } + } + else + { + //moving upwards requires we write the top row first + for (y = 0; y < h; y++) + { + memmove(ctx->buffer + (dl + (dt+y)*ctx->width), ctx->buffer + (sl + (st+y)*ctx->width), w*4); + } } } } @@ -65,22 +130,37 @@ private: unsigned int *out = ctx->buffer; const unsigned int *in = (const unsigned int*)bitmap_in; int x, y; - int t = copy_rects[i].top() - bitmap_rect.top(); - int l = copy_rects[i].left() - bitmap_rect.left(); + int t = copy_rects[i].top(); + int l = copy_rects[i].left(); int r = copy_rects[i].width() + l; int b = copy_rects[i].height() + t; - unsigned int instride = bitmap_rect.width() - (r - l); - unsigned int outstride = ctx->width - (r - l); + int w, h; - out += copy_rects[i].left(); - out += copy_rects[i].top() * ctx->width; + //Clip the rect to the display. This should generally happen anyway, but resizes can be lagged a bit with the whole multi-process/thread thing. + //don't need to clip to the bitmap rect, that should be correct. + if (l < 0) + l = 0; + if (t < 0) + t = 0; + if (r > ctx->width) + r = ctx->width; + if (b > ctx->height) + b = ctx->height; + w = r - l; + h = b - t; - in += l; - in += t * bitmap_rect.width(); + unsigned int instride = bitmap_rect.width() - (w); + unsigned int outstride = ctx->width - (w); - for (y = t; y < b; y++) + out += l; + out += t * ctx->width; + + in += (l-bitmap_rect.left()); + in += (t-bitmap_rect.top()) * bitmap_rect.width(); + + for (y = 0; y < h; y++) { - for (x = l; x < r; x++) + for (x = 0; x < w; x++) { *out++ = *in++; } @@ -182,16 +262,47 @@ static void Dec_Key (void *vctx, int code, int unicode, int isup) wchar_t wchr = unicode; if (code >= 178 && code < 178+6) - ctx->wnd->mouseButton(code - 178, !isup); + { + code = code - 178; + //swap mouse2+3 + if (code == 1) + code = 2; + else if (code == 2) + code = 1; + ctx->wnd->mouseButton(code, !isup); + } else if (code == 188 || code == 189) - ctx->wnd->mouseWheel(0, (code==189)?-30:30); + { + if (!isup) + ctx->wnd->mouseWheel(0, (code==189)?-30:30); + } else { if (code) { int mods = 0; if (code == 127) + code = 0x08; + else if (code == 140) //del code = 0x2e; + else if (code == 143) //home + code = 0x24; + else if (code == 144) //end + code = 0x23; + else if (code == 141) //pgdn + code = 0x22; + else if (code == 142) //pgup + code = 0x21; + else if (code == 139) //ins + code = 0x2d; + else if (code == 132) //up + code = 0x26; + else if (code == 133) //down + code = 0x28; + else if (code == 134) //left + code = 0x25; + else if (code == 135) //right + code = 0x27; ctx->wnd->keyEvent(!isup, mods, code, 0); } if (unicode && !isup) @@ -214,6 +325,10 @@ static void Dec_ChangeStream(void *vctx, char *newstream) ctx->wnd->refresh(); else if (!strcmp(newstream+4, "transparent")) ctx->wnd->setTransparent(true); + else if (!strcmp(newstream+4, "focus")) + ctx->wnd->focus(); + else if (!strcmp(newstream+4, "unfocus")) + ctx->wnd->unfocus(); else if (!strcmp(newstream+4, "opaque")) ctx->wnd->setTransparent(true); else if (!strcmp(newstream+4, "stop"))